vue2中props的type为Function时,default 中使用this为null

父组件

<template>
<div>
  <el-row>
    <Tree/>
  </el-row>
  <el-row>
    <Tree :handleNodeClick="handleNodeClick" />
  </el-row>
</div>
<script>
import Tree from './Tree'
export default {
  components: {
    Tree
  },
  methods: {
    handleNodeClick(data) {
      console.log('父组件', data, 'this', this);
    }
  },
}
</script>

子组件

<template>
<div >
  <el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</div>
</template>
<script>
export default {
  props: {
    handleNodeClick: {
        type: Function,
        default (data) {
            // this为空
            console.log('子组件', data, 'this', this)
        }
    }
  }
}
</script>

上面的代码 在父组件不传handleNodeClick时,想要子组件使用default函数,但是访问不到this 要怎么办?

阅读 4.9k
1 个回答

发现有些场景下this是本组件实例,有些场景下this为null,调试后发现不行的场景是vue主动绑定this 为 null,下面是 vue2.6.11 版本构建的 vue.esm.js

function createFnInvoker (fns, vm) {
  function invoker () {
    var arguments$1 = arguments;

    var fns = invoker.fns;
    if (Array.isArray(fns)) {
      var cloned = fns.slice();
      for (var i = 0; i < cloned.length; i++) {
        invokeWithErrorHandling(cloned[i], null, arguments$1, vm, "v-on handler");
      }
    } else {
      // return handler return value for single handlers
      return invokeWithErrorHandling(fns, null, arguments, vm, "v-on handler")
    }
  }
  invoker.fns = fns;
  return invoker
}

function invokeWithErrorHandling (
  handler,
  context,
  args,
  vm,
  info
) {
  var res;
  try {
    // 就是这行
    res = args ? handler.apply(context, args) : handler.call(context);
    if (res && !res._isVue && isPromise(res) && !res._handled) {
      res.catch(function (e) { return handleError(e, vm, info + " (Promise/async)"); });
      // issue #9511
      // avoid catch triggering multiple times when nested calls
      res._handled = true;
    }
  } catch (e) {
    handleError(e, vm, info);
  }
  return res
}

解决方法是在子组件中手动bind一次

<template>
<div >
  <el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</div>
</template>
<script>
export default {
  props: {
    propsHandleNodeClick: {
        type: Function,
        default (data) {
            console.log('子组件', data, 'this', this)
        }
    }
  },
  methods: {
    handleNodeClick (...rest) {
      // 根据函数的 name 属性来判断 父组件有没有传入方法,因为这里用了'default' 所以 函数名里不能有 'default'
      if (this.propsHandleNodeClick.name.indexOf('default') > -1) {
          this.handleNodeClick = this.propsHandleNodeClick.bind(this)
      } else {
        // 如果父组件有传入方法,基本上this的指向是父组件实例 不需要改变this
        this.handleNodeClick = this.propsHandleNodeClick
      }
      this.handleNodeClick(...rest)
    }
  }
}
</script>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题