Vue自定义指令中无法获取this的问题及解决

目录
  • 自定义指令中无法获取this
    • 解决方法
  • Vue使用this的这几个坑你都知道吗
    • 一、普通函数
    • 二、Vue中的this

自定义指令中无法获取this

问题

最近在使用自定义指令时遇到一个问题,我想在指令里通过this直接去访问vue实例数据,但是显示未定义,经大佬提醒,里面的this很可能不是指向vue实例

解决方法

在函数里增加第三个参数vnode,vnode.context就是指向当前的vue实例

总结

指令里的this不是指向vue实例,可以使用vnode.context获取this

自定义指令可传入以下参数

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
  • name:指令名,不包括 v- 前缀。
  • value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
  • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
  • expression:字符串形式的指令表达式。例如 v-my-directive=“1 + 1” 中,表达式为 “1 + 1”。
  • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 “foo”。
  • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
  • vnode:Vue 编译生成的虚拟节点。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

Vue使用this的这几个坑你都知道吗

最近写vue项目遇到很多this指向的问题,今天来写一下我总结的this指向

看了很多文章、博客,对于正常函数,谁调用的它,this就指向谁,而箭头函数没有this,它的this指向一般就是上下文中,与谁调用它没关系。

但是在Vue实例中,methods、生命周期函数中如果用的是正常函数,那么它的this就指向Vue实例,也就是vm(本文中的vm是指const vm = new Vue({···})中的vm);如果是箭头函数,在非严格模式下this就指向window对象,严格模式下是undefind。

这里我分别来说一下普通函数中的this和Vue中的this

一、普通函数

普通函数的this是由动态作用域决定,它总指向于它的直接调用者。具体可以分为以下四项:this总是指向它的直接调用者, 例如 obj.func() ,那么func()里的this指的是obj。在默认情况(非严格模式,未使用 'use strict'),如果函数没有直接调用者,this为window;在严格模式下,如果函数没有直接调者,this为undefined使用call,apply,bind绑定的,this指的是绑定的对象

简单总结: 

(1)全局函数中的this指向window

(2)对象中的方法(函数)中的this,指向对象,理解:obj.m=function(){},m和fn等价,因此调用m也相当于调用fn,原理同3)

(3)构造函数中的this指向调用该构造函数的实例对象

(4)特殊this指向: 箭头函数没有绑定this,this继承自外围作用域,理解:查看上一层级的函数的this的指向,继承它!!

(5)绑定this指向:apply,call,bind绑定的对象

接下来用实例来介绍下各种this问题

1.全局环境下,this 始终指向全局对象(window), 无论是否严格模式

    console.log(this.document === document); // true
    // 在浏览器中,全局对象为 window 对象:
    console.log(this === window); // true
    this.a = 3;
    console.log(window.a); // 3

2.函数直接调用,普通函数内部的this分两种情况,严格模式和非严格模式

    //严格模式下, this为undefined
    function f2(){
      "use strict"; // 这里是严格模式
      return this;
    }
    f2() === undefined; // true
    //而非严格模式下,this 默认指向全局对象window
    function f1(){
      return this;
    }
    f1() === window; // true

3.对象中的this,对象内部方法的this指向调用这些方法的对象

    //函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
    //多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调
    //用方法的this指向内部对象, 而非window)。
    //例一:
    var obj = {
      prop: 37,
      f: function() {
        return this.prop;
      }
    };
    console.log(obj.f());  //37
    var a = obj.f;
    console.log(a());  //undefined
    
    var obj = {prop: 37};
    
    function independent() {
      return this.prop;
    }
    
    obj.f = independent;
    
    console.log(obj.f()); //37
    
    //例二:
    obj.b = {
      num: independent,
      prop: 42
    };
    console.log(obj.b.num()); //42

4.原型链中this,原型链中的方法的this仍然指向调用它的对象

    var obj = {
      f : function(){ 
        return this.a + this.b; 
      }
    };
    var p = Object.create(obj);
    p.a = 1;
    p.b = 4;
    
    console.log(p.f()); // 5
//在p中没有属性f,当执行p.f()时,会查找p的原型链,找到 f 函数并执行,但这与函数内部this指向对象 //p 没有任何关系,只需记住谁调用指向谁。
 
//以上对于函数作为getter & setter 调用时同样适用。

5.构造函数中this,构造函数中的this与被创建的新对象绑定

注意:当构造器返回的默认值是一个this引用的对象时,可以手动设置返回其他的对象,如果返回值不是一个对象,返回this。

6.call & apply

当函数通过Function对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的this值可绑定到 call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。

7.bind 方法

bind方法在ES5引入, 在Function的原型链上, Function.prototype.bind。通过bind方法绑定后, 函数将被永远绑定在其第一个参数对象上, 而无论其在什么情况下被调用。

8.DOM事件处理函数,当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素 (针对于addEventListener事件)

  // 被调用时,将关联的元素变成蓝色
    function bluify(e){
      console.log(this);//在控制台打印出所点击元素
      e.stopPropagation();//阻止时间冒泡
      e.preventDefault();//阻止元素的默认事件    
      this.style.backgroundColor = '#A5D9F3';
    }
    var elements = document.getElementsByTagName('*');// 获取文档中的所有元素的列表
    // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
    for(var i=0 ; i<elements.length ; i++){
      elements[i].addEventListener('click', bluify, false);
    }

9.内联事件,内联事件中的this指向分两种情况:

  • 当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素
  • 当代码被包括在函数内部执行时,其this指向等同于函数直接调用的情况,即在非严格模式指向全局对象window, 在严格模式指向undefined。

10.setTimeout & setInterval,对于延时函数内部的回调函数的this指向全局对象window(当然我们可以通过bind方法改变其内部函数的this指向)

    //默认情况下
    function Person() {  
        this.age = 0;  
        setTimeout(function() {
            console.log(this);
        }, 3000);
    }
    //通过bind绑定
    function Person() {  
        this.age = 0;  
        setTimeout((function() {
            console.log(this);
        }).bind(this), 3000);
    }
    var p = new Person();//3秒后返回构造函数新生成的对象 Person{...}

11.箭头函数中的 this,由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值

    // call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。
    //考虑到 this 是词法层面上的,严格模式中与 this 相关的规则都将被忽略。(可以忽略是否在严格
    //模式下的影响)
    //因为箭头函数可以捕获其所在上下文的this值 所以:
    function Person() {  
        this.age = 0;  
        setInterval(() => {
            this.age++;// 回调里面的 `this` 变量就指向了期望的那个对象了
        }, 3000);
    }
    var p = new Person();
    //以上代码可以得到我们所以希望的值,下图可以看到,在setTimeout中的this指向了构造函数新生成
    //的对象,而普通函数指向了全局window对象

二、Vue中的this

1.Vue methods

来看看官方文档给出的解释:

methods 将被混入到 Vue 实例中。可以直接通过 实例vm 访问这些方法,或者在指令表达式中使用。方法中的 this自动绑定为 Vue 实例(vm)。

注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。

长话短说,官方的意思是:在Vue实例中,methods中如果用的是正常函数,那么它的this就指向Vue实例;如果是箭头函数,this就指向window对象;

总结:

Vue methods 中不应该箭头函数定义methods函数,因为箭头函数绑定了父级作用域上下文,所以 this 打印出的结果是Window 对象;不使用箭头函数的情况下,this 实际上是指向了一个 Proxy 对象。

原因是vue 内部实际上对methods属性中的方法进行了遍历,将对应的方法通过bind绑定了this,使得this指向实例vm

2.Vue中生命周期钩子和自定义方法中的this指向当前的 Vue 实例

所有的生命周期钩子自动绑定 this 上下文到实例中,因此你可以访问数据,对 property 和方法进行运算。这意味着你不能使用箭头函数来定义一个生命周期方法 (例如 created: () => this.checkTodos())。这是因为箭头函数绑定了父上下文,因此 this 与你期待的 Vue 实例不同,this.checkTodos 的行为未定义。

3. Vue 中回调函数中的 this:

  • 若回调函数为匿名函数,非严格模式下指向 window,严格模式下为 undefined。
  • 若回调函数为自定义方法,则 this 指向 Vue 实例。
  • 若回调函数为 箭头函数,则 this 指向 Vue 实例。

4. Vue 中 addEventListener 中的 this

通常,事件监听函数中的 this 都指向绑定事件的那个元素, 但是在 Vue 中,监听函数中的 this 也指向 Vue 实例

5.在data里定义Object类型的变量时的this

在data里定义Object类型的变量时,会发现Object中访问不到vue的this属性,例如:

export default {
  data(){
    return {
      a: "123",
      b: {
        c: this.a
      }
    };
  },
  created() {
    console.log("b: ", this.b.c); // undefined
  }
}

想在b中访问this.a的数据,直接访问会返回undefined,因为这时c中的this指向的是b。这种情况可以用到Object的get属性进行属性定义,例如:

export default {
  data(){
    return {
      a: "123",
      b: {
        _target: () => this,
        get target() {
          return this._target();
        },
 
        get c() {
          return this.target.a;
        },
      },
    };
  },
  created() {
    console.log("b: ", this.b.c); // 123
  }
}

此处将this映射到了Object变量内部,然后通过get的形式定义属性并获取,这样就解决问题啦。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 详解在Vue中通过自定义指令获取dom元素

    vue.js 是数据绑定的框架,大部分情况下我们都不需要直接操作 DOM Element,但在某些时候,我们还是有获取DOM Element的需求的: 在 vue.js 中,获取某个DOM Element常用的方法是将这个元素改成一个组件 (component),然后通过 this.$el 去获取,但是在一些很小的项目里,在一些没有使用 webpack 等构建工具的项目中,创建一个组件并不是那么值得,所以 vue 提供了另一种操作DOM元素的方式,就是自定义指令 (directive) : 自定

  • 解决VUE自定义拖拽指令时 onmouseup 与 click事件冲突问题

    功能描述: 如图,右侧悬浮菜单按钮,只支持上下方向拖动,点击时展开或关闭菜单. BUG说明: 鼠标上下方向拖拽,如果松开时鼠标位于悬浮按钮上会默认执行click事件,经验证,click事件与mouse事件的执行顺序为onmousedown =>onmouseup =>onclick,意味着在click事件执行时会与与其相关的mouse事件冲突. 解决方案: 因为click事件执行时间短,所以利用鼠标拖动的时间差作为标志,在拖拽事件中计算鼠标从onmousedown 到onmouseup 所用的

  • 详解Vue自定义指令及使用

    一.什么是指令 学习 vue 的时候肯定会接触指令,那么什么是指令呢? 在 vue 中提供了一些对于页面和数据更为方便的输出,这些操作就叫做指令,以 v-xxx 表示,比如 html 页面中的属性 <div v-xxx ></div> 比如在 angular 中 以 ng-xxx 开头的就叫做指令 指令中封装了一些 DOM 行为,结合属性作为一个暗号,暗号有对应的值,根据不同的值,会进行相关 DOM 操作的绑定,即可以进行一些模板的操作 vue 中常用的一些内置 v- 指令 v-t

  • Vue自定义指令中无法获取this的问题及解决

    目录 自定义指令中无法获取this 解决方法 Vue使用this的这几个坑你都知道吗 一.普通函数 二.Vue中的this 自定义指令中无法获取this 问题 最近在使用自定义指令时遇到一个问题,我想在指令里通过this直接去访问vue实例数据,但是显示未定义,经大佬提醒,里面的this很可能不是指向vue实例 解决方法 在函数里增加第三个参数vnode,vnode.context就是指向当前的vue实例 总结 指令里的this不是指向vue实例,可以使用vnode.context获取this

  • vue 自定义指令自动获取文本框焦点的方法

    HTML: <p><b v-show="show">{{tag}}</b><input v-focus v-model="tag" :hidden="show" type="text"></p> js: 官方例子: directives: { focus: { // 指令的定义 inserted: function (el) { el.focus() } } } 我的

  • 在vue自定义组件中使用 v-model指令详情

    目录 一.前言 1.技术点提前知 二.在自定义的vue组件中使用v-model 1.效果演示图 2.自定义组件代码示例 3.在父组件使用自定义组件 三.优写时刻 一.前言 如何实现在自定义的vue组件中使用v-model,. 起先觉得挺简单,事实也挺简单,但似乎又没那么简单.因为深谈这涉及指令原理.数据绑定实现原理. 1.技术点提前知 要想在自定义组件中使用v-model,使用上其实就简单几步,这里以自定义input组件为例. 关键步骤: 1.props的使用.在自定义的vue文件中,声明父组件

  • Vue自定义指令实现checkbox全选功能的方法

    最近做的一个项目需要用到Vue实现全选功能,参考了一下网上的做法,发现用属性计算的复用性不高,于是选用自定义指令,但网上的做法大多是会对原始数据有一定的格式要求,而且没有返回结果,于是做了改进. 上代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id

  • 详解Angularjs 自定义指令中的数据绑定

    有关自定义指令的scope参数,网上很多文章都在讲这3种绑定方式实现的效果是什么,但几乎没有人讲到底怎么使用,本篇希望聊聊 到底怎么用 这个话题. 一. 自定义指令 自定义指令,是 Angularjs 用来实现组件化的方式,相比于 React 和 Vue 的组件化方式,它真的很复杂,自定义指令太重了,它暴露了太多可供定制的参数,以至于普通的开发者完全不知道要用它来做什么而将其束之高阁,毕竟一般的业务逻辑通过controller和service就已经可以完成了. 自定义指令在 Angularjs

  • 使用vue自定义指令开发表单验证插件validate.js

    这段时间在进行一个新项目的前期搭建,新项目框架采用vue-cli3和typescirpt搭建.因为项目比较轻量,所以基本没有使用额外的ui组件,有时候我们需要的一些基础组件我就直接自己开发了.今天就来介绍一下如何利用vue的自定义指令directive来开发一个表单验证插件的过程. 1.vue插件开发 关于vue的插件开发,官方文档里有很清晰的说明,详情可以去阅读开发文档.我自己开发的表单验证插件validate.ts和loading,messageBox插件都是利用了这种方式.今天先来看表单验

  • 基于Vue自定义指令实现按钮级权限控制思路详解

    思路: 登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token,拿到token之后(我会将这个token存贮到sessionStorage中,保证刷新页面后能记住用户登录状态),前端会根据token再去拉取一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息). 权限验证:通过token获取用户对应的 role,自定义指令,获取路由meta属性里btnPermissions( 注: meta.btnPermissions是存放按钮

  • vue自定义指令实现仅支持输入数字和浮点型的示例

    再开始本篇的讨论之前,先思考几个问题: 使用html元素属性type='number'是否可以满足要求 Vue中指令一般被设计用来操作dom元素的,而vue视图是基于数据模型的,如何在操作dom的同时,同时更新数据 你定义的指令不能只能在input元素上使用,还要支持在其父元素上使用,自定义组件及第三方组件上使用 你的指令是不是支持局部作用域,比如for循环渲染的数据的单元item,如何识别这个item进行数据更新和dom操作 如何控制字符数目,超出禁止输入 如何实现全局性的功能定义,从而在各个

  • vue自定义指令和动态路由实现权限控制

    功能概述: 根据后端返回接口,实现路由动态显示 实现按钮(HTML元素)级别权限控制 涉及知识点: 路由守卫 Vuex使用 Vue自定义指令 导航守卫 前端工程采用Github开源项目Vue-element-admin作为模板,该项目地址:Github | Vue-element-admin. 在Vue-element-admin模板项目的src/permission.js文件中,给出了路由守卫.加载动态路由的实现方案,在实现了基于不同角色加载动态路由的功能.我们只需要稍作改动,就能将基于角色加

  • 实现一个Vue自定义指令懒加载的方法示例

    在项目中如果有大量的图片需要加载的时候,就可以考虑使用懒加载了,懒加载其实就是监听浏览器的滚动,当滚动到一定的范围的时候就将图片的真实路径赋给src,然后取消监听.实现的方法也比较简单,可以通过懒加载的插件实现,也可以手写,手写通过vue自定义指令来实现,一般情况自定义指令用的也不多,比较vue自带的就够用了,大型复杂的项目的可能用的多. 什么是图片懒加载 当我们向下滚动的时候图片资源才被请求到,这也就是我们本次要实现的效果,进入页面的时候,只请求可视区域的图片资源这也就是懒加载. 比如我们加载

随机推荐