关于Vue-extend和VueComponent问题小结

在一个非单文件组件中(一个文件中包含n个组件,最常见的就是单个html文件中存在多个组件),如果我们需要在这个文件中创建n个组件,然后再页面上展示,这时候我们就需要先定义组件,然后注册组件,最后使用组件。在定义组件这一步,我们就需要使用到 extend 这个方法。当然,也可以在一个html文件中使用多个 new Vue () 来注册组件,但是这么做有问题,下面再说。

Vue.extend(option)

官方文档解释:使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。

组件选项:templete模板(el属性只能在 new Vue() 时使用)、data数据、methods方法、computed计算属性等等正常组件拥有的。

我的理解:首先 extend 是 Vue 自带的一个全局方法,该方法接收一个对象作为参数,在实例化的时候,通过传递的参数将一个空的 Vue实例 进行扩展,并以此来创造出一个 Vue 子类,也就是我们说的 Vue 组件。

使用方法:

1、非单文件组件内部所有组件全部使用 Vue.extend() 方式注册(未指定根组件,无法渲染)

2、非单文件组件中使用 new Vue() 注册根组件,其余子组件则使用 Vue.extend() 方式注册。

3、全部使用 new Vue() 注册组件(若是存在组件嵌套,则子组件内部双向绑定的的数据失效)

1、全部使用 Vue.extend() 方式注册组件

const vm2 = Vue.extend({
  template:
    `<div id='root2'>
    {{msg}}
  </div>`,
  data() {
    return {
      msg: 'root2',
      count: 2,
      pets: 'dog'
    }
  }
})

const vm1 = Vue.extend({
  template:
    `<div id='root1'>
      {{msg}}
      <!-- 使用 root2 组件 -->
      <vm2 />
    </div>`,
  data() {
    return {
      msg: 'root1',
      count: 1,
      pets: 'dog'
    }
  },
  components: {
    // 注册子组件
    vm2
  }
})

无法展示,页面也不会报错,因为根本没有指定根组件进行渲染

2、使用第二种方式分别注册子组件和根组件

注册子组件

const vm1 = Vue.extend({
  template:
  `<div id='root2'>
    {{msg}}
    <input v-model="count" />
  </div>
  `,
  data() {
    return {
      msg: 'root2',
      count: 2,
      pets: 'dog'
    }
  }
})

注册根组件

// 注册根组件
const vm = new Vue({
  el: '#root1',
  data() {
    return {
      msg: 'root1',
      count: 1,
      pets: 'dog'
    }
  },
  components: {
    // 注册子组件
    vm1
  }
})

根组件以及子组件使用

<div id='root1'>
  {{msg}}
  <input v-model="count" />
  <!-- 使用 root2 组件 -->
  <vm1 />
</div>

页面展示效果正常,且双向绑定数据正常

3、全部使用 new Vue 定义组件。其实在正常的开发中,这个方法用的极少,因为我们的开发一般都是单文件组件,在工程中每个组件都是通过 new Vue() 创建的,直接挂载到 根组件 app上。但是在单文件组件中,我们一般不使用多个 new Vue() 来创建组件,这是因为在使用 new Vue() 时,必须要传入一个 el 属性,这样会导致html页面上存在多个根节点,如果你的根节点嵌套了,那嵌套的根节点中绑定的数据会失效,不会展示。例如:

<div id='root1'>
  {{msg}}
  <input v-model="count" />
  <select name="pets" id="pet-select" v-model="pets">
    <option value="">--Please choose an option--</option>
    <option value="dog">Dog</option>
  </select>

  <div id='root2'>
    {{msg}}
    <input v-model="count" />
    <select name="pets" id="pet-select" v-model="pets">
      <option value="">--Please choose an option--</option>
      <option value="dog">Dog</option>
    </select>
  </div>
</div>

在这个 html 文件中,存在两个根节点 ,root1、root2,两个跟节点内部的子节点完全一样,绑定的数据也完全一样,但是 root1根节点包裹住了 root2根节点。

const vm = new Vue({
  el: '#root1',
  data() {
    return {
      msg: 'root1',
      count: 1,
      pets: 'dog'
    }
  },
})

const vm1 = new Vue({
  el: '#root2',
  data() {
    return {
      msg: 'root2',
      count: 2,
      pets: 'dog'
    }
  }
})

按照原本的想法,两个节点展示的数据应该完全一样,但是在页面上的效果是这样的。

可以看到,只有外部的root1根节点展示了对的数据, root2的根节点数据要么为空不展示,要么展示的是错误数据。

如果我们使用 Vue.extend() 来注册子组件又会是什么情况呢?

首先,注册root2组件,其实就是将root2的所有节点放在了 templete 属性内部,用字符串模板包裹

const vm1 = Vue.extend({
  template:
    `<div id='root2'>
    {{msg}}
    <input v-model="count" />
    <select name="pets" id="pet-select" v-model="pets">
      <option value="">--Please choose an option--</option>
      <option value="dog">Dog</option>
    </select>
  </div>`,
  data() {
    return {
      msg: 'root2',
      count: 2,
      pets: 'dog'
    }
  }
})

2、在父组件中注册 root2 组件

const vm = new Vue({
  el: '#root1',
  data() {
    return {
      msg: 'root1',
      count: 1,
      pets: 'dog'
    }
  },
  components: {
    vm1
  }
})

3、使用 root2 组件

<div id='root1'>
  {{msg}}
  <input v-model="count" />
  <select name="pets" id="pet-select" v-model="pets">
    <option value="">--Please choose an option--</option>
    <option value="dog">Dog</option>
  </select>
  <!-- 使用 root2 组件 -->
  <vm1 />
</div>

4、页面效果

结论:如果是在非单组件文件(或者是html页面),最好是只用 一个new Vue()注册一个根组件,其余子组件则是用 Vue.extend() 注册。否则如果使用 new Vue() 注册所有组件的话,若是存在组件包裹的情况,则被包裹的组件内部双向数据绑定会失效。

VueComponent

在组件定义之后,我们其实还没有去理解这个过程和内部操作,下面我们就来剖析一下,看看在 Vue.extend() 之后,发生了什么。

首先,我们来看看 Vue.extend() 之后,返回的是一个什么东西。

样例代码就不贴了,就是上面的 vm1 实例。打印 vm1 之后,看看是个啥

打印之后发现,这玩意是个函数,而且还是个构造函数。在这个函数里面啥操作也没做,只不过调用了 _init() 方法。

Vue.extend = function (extendOptions) {
 /*****其余操作***/
  var Sub = function VueComponent(options) {
    console.log("VueComponent被调用了");
    this._init(options);
  };
  /*****其余操作***/
  return Sub;
};
}

所以说,

1、组件的本质就是一个 【VueComponent 的构造函数】,且这个函数是 Vue.extend() 生成的。

2、在使用组件时,我们只需要写上组件标签,Vue 会自动帮我们生成 组件的实例对象( 因为组件的本质就是一个构造函数,构造函数被调用之后,当然会产生实例对象),即 Vue 帮我们执行的 new VueCopmonennt(options)

3、特别注意,每次调用 Vue.extend(),返回的都是一个新的组件,因为是通过函数返回的。这个地方我们看看上面的源码就能知道,因为 每次调用之后返回的 Sub 都是不一样的。

4、关于this指向,

a、通过 Vue.extend() 配置的组件,在data,methods,component,watch等可能用到 this 的地方,this 指向的是 【VueComponent 的实例对象】

b、通过new Vue() 配置的组件,在data,methods,component,watch等可能用到 this 的地方,this 指向的是 【Vue 的实例对象】

验证一下:

分别在上面的实例 vm,vm1上配置 show 方法,在方法内部打印当前this

点击按钮之后,查看 this 指向

展开的地方太大了,就不展开了,但是在控制台上对比发现,除了 一个是 Vue {} 一个是 VueComponent {} 之外,内部的所有属性全部一致,包括数据劫持,数据代理,底层方法等等。

组件管理

之前说的Vue.extend(option) 这个模块时,说到了非单文件组件内部,最好是使用Vue.extend(option) 来定义子组件,然后使用 new Vue(option) 来注册根组件,从而使得 根组件好方便管理子组件,那么从那里能看出来管理状态呢?

看看上面的this 指向问题,展开之后,发现 一个 $children属性,这是一个数组

在 new Vue() 配置的组件中,发现存在一个 VueComponent {} 实例对象,这个对象指向的就是 vm1实例对象

而在 Vue.extend() 配置的组件中,发现这是一个空数组,这就是因为, 根组件调用了 vm1子组件,而 vm1子组件,内部是没有调用别的子组件的。

这就是 Vue 的组件管理模式

总结

如何使用 Vue.extend() 定义一个组件:

1、Vue.extend(option) 和 new Vue(option) 创建组件时所传入的 option 配置项几乎一样.

区别在于:

(a)、el不能指定:所有的组件最终只会由一个vm管理,由这个vm中的 el 指定挂载容器

(b)、data必须写成函数:避免组件复用时,数据存在引用关系。

Vue.extend() 定义组件的本质:

本质上是 调用了 VueComponent () 这个构造函数,去返回了一个 【VueComponent 实例对象】,且每次在Vue.extend() 调用时,返回的组件实例对象都不一样

非单文件组件中定义根组件和子组件

原则上,默认一个非单文件组件中 只存在一个 new Vue() 定义的根组件,可以有无数个 Vue.extend() 定义的子组件,这是因为,如果所有组件都用 new Vue() 定义,那么如果存在组件包裹的情况,子组件内部双向绑定的数据不会生效。如果都用 Vue.extend() 定义组件,那么则没有指定根组件,无法渲染。

this指向问题

使用 new Vue() 定义的组件,在组件内部能用到 this 的地方,this指向为【Vue实例对象】

使用 Vue.extend() 定义的组件,~~~~~~~~~~~~~this指向为【VueComponent实例对象】

官网补充

这里说明了,使用 VueComponent 和 new Vue 的异同。但是其实还有一点:在 new Vue 中,传递的 data 属性,可以是对象,也可以是函数( 当然,我们还是推荐函数写法 ),但是在VueComponent 中传递的 data 属性,则只能是函数,因为 new Vue 注册的是 根组件,不存在复用情况,data中的属性不存在引用关系,不会导致数据错乱,但是VueComponent 则不同

(0)

相关推荐

  • Vue extend的基本用法(实例详解)

    Vue.extend 属于 Vue 的全局 API,在实际业务开发中我们很少使用,因为相比常用的 Vue.component 写法使用 extend 步骤要更加繁琐一些. 我们创建Vue实例时,都会有一个el选项,来指定实例的根节点,如果不写el选项,那组件就处于未挂载状态.Vue.extend 的作用,就是基于 Vue 构造器,创建一个' 子类 ',它的参数跟new Vue的基本一样,但data要跟组件一样,是个函数,再配合$mount,就可以渲染组件,并且挂载到任意指定的节点上,比如body

  • vue extend+promise封装全局弹窗组件

    本文实例为大家分享了vue + element ui实现锚点定位的具体代码,供大家参考,具体内容如下 因为项目没有引入第三方UI库,所以所有的公共组件都需要自己封装现在需要一个全局的弹窗,要有promise异步处理 实现后的效果 // components/confirm文件 <template>   <div class="popup-wrap" v-if="showPopup">     <div class="popup

  • Vue.extend实现组件库message组件示例详解

    目录 概述 Vue.extend message 组件配置对象(就是.vue文件) message 生成组件的函数 使用方法 效果图 总结 概述 当我们使用组件库的时候,某些组件并不是直接放到模板当中进行使用,而是通过api的方式调用生成组件并且挂在到我们的页面中,其中最常见的就是message组件,我们在组件库中看到的多数都是api调用的方式生成.记录自己基本实现message组件. Vue.extend 在vue中,要实现通过api方式实现组件的使用,这个aip是必不可少的,因此我们先了解下

  • vue中使用mixins/extends传入参数的方式

    目录 使用mixins/extends传入参数 vue mixins的原理 使用mixins/extends传入参数 最近做报表页面,基本都是列表页面,所以想用mixins. 但是接口的url不同,于是考虑怎么才能传入参数去适配各个页面. 后来发现mixin文件可以写个函数,接受传递过来的参数,然后return一个对象. 大概如下: mixin.js export default function(config) {     let {         listUrl="",    

  • Vue.extend 登录注册模态框的实现

    模态框是我们 UI 控件中一个很重要的组件,使用场景有很多种,我们在 Vue 组件中创建模态框组件而用到的一个知识点是利用 Vue.extend 来创建. 文档中的解释是 在最近在做一个常用的类似下面的 登录/注册 业务场景时,利用 Vue.extend 来改善我们的代码,使我们代码逻辑更清晰化. 需求:点击登录或注册出现各自的模态框. 我们对于这种常见的登录注册业务,一般都是分为 Sigin.vue 和 Register.vue 两个组件,然后把两个组件写入 App.vue 组件中,或者是 l

  • Vue extend使用示例深入分析

    目录 一.使用场景 二.补充组件注册 三.深度解析 Vue.extend()虽然已近用过很多次了,但都没有深入思考过这个东西,仔细想了想,有点意思 一.使用场景 按需使用组件,也叫懒加载,性能蹭蹭往上走 扩展的组件,其自由度高到你无法想象 二.补充组件注册 平日里,我们使用组件: 黄金玩家: <template> <A/> </template> import A from "./A.vue"; export default { components

  • 如何巧用Vue.extend继承组件实现el-table双击可编辑(不使用v-if、v-else)

    目录 问题描述 效果图 代码思路 代码思路中的三个问题解答 问题一:如何创建一个el-input标签? 问题二三:el-input标签和span标签的来回替换恢复 完整代码 目录结构 用于继承的el-input组件 用于继承的span组件 统一继承并暴露data.js文件 使用继承的three.vue组件 总结 问题描述 有一个简单的表格,产品要求实现双击可编辑 看了一下网上的帖子,大多数都是搞两部分dom,一块是输入框,用于编辑状态填写:另一块是普通标签,用于在不编辑显示状态下呈现单元格文字内

  • 通过vue.extend实现消息提示弹框的方法记录

    前提回顾 在项目开发中我们经常使用的组件注册分为两种,一个是全局注册和另一个是局部注册,假设我们的业务场景是用户在浏览注册页面时,点击页面中的注册按钮后,前端根据用户的注册信息先做一次简单的验证,并根据验证弹出一个对应消息提示弹框 我们拿到这个需求后,便开始着手准备要通过局部注册消息弹框组件的方法来实现这个场景,在通过局部注册消息弹框组件的方法解决完这个需求后,自然是沾沾自喜,紧接着又迎来了一个需求,该需求是用户在点击该注册按钮时,点击几次就要出现几次这个消息弹框,你开始犯了难,并思考难道我要在

  • vue 2.5.1 源码学习 之Vue.extend 和 data的合并策略

    1. 子类父类 2.Vue.extend()      //创建vue的子类 组件的语法器 Vue.extend(options) Profile().$mount('#app') // 挂在app上,并替换app 新建 initExend ==> Vue.extend 3. strat.data ==> if(!vm){子组件中data的值是一个方法function ==> mergeDataorFn()} // 数据的合并 ==> else {} //通过实例绑定的data 实

  • 关于Vue-extend和VueComponent问题小结

    在一个非单文件组件中(一个文件中包含n个组件,最常见的就是单个html文件中存在多个组件),如果我们需要在这个文件中创建n个组件,然后再页面上展示,这时候我们就需要先定义组件,然后注册组件,最后使用组件.在定义组件这一步,我们就需要使用到 extend 这个方法.当然,也可以在一个html文件中使用多个 new Vue () 来注册组件,但是这么做有问题,下面再说. Vue.extend(option) 官方文档解释:使用基础 Vue 构造器,创建一个“子类”.参数是一个包含组件选项的对象. 组

  • Vue中Vue.extend()的使用及解析

    目录 Vue Vue.extend()的使用 应用场景 简单实用 使用Vue.extend()编写vue插件 Vue.extend() 如何编程式使用组件呢 具体使用 Vue Vue.extend()的使用 Vue.extend 属于 Vue 的全局 API,在实际业务开发中我们很少使用,因为相比常用的 Vue.component 写法使用 extend 步骤要更加繁琐一些.但是在一些独立组件开发场景中,Vue.extend + $mount 这对组合是我们需要去关注的. 应用场景 在 vue

  • Vue.extend构造器的详解

    Vue.extend构造器的详解 1.简单介绍 Vue.extend(options) 参数:对象 用法:使用Vue构造器,创建一个"子类",参数是一个包含组件选项的对象,其中,data选项中必须是函数 描述:Vue.extend返回的是一个"扩展实例构造器",也就是预设了部分选项的Vue的实例构造器,它常常服务于Vue.component用来生成组件,可以简单理解为当在模板中遇到该组件作为标签的自定义元素时,会自动调用"扩展实例构造器"来生产组

  • 用Vue.extend构建消息提示组件的方法实例

    前提 前段时间自己做的vue练手项目,需要一个通用的消息提示组件,但是消息提示这种组件我更想用方法来调用,而不是在各个页面上都添加个组件(那样感觉很麻烦,重度懒癌患者),于是就上网差查了查,并研究了ElementUI的message源码.自己弄出来一个简陋的消息提示组件 Vue.extend是什么 按照官方文档说法,他是一个类构造器,用来创建一个子类vue并返回构造函数,而Vue.component它的任务是将给定的构造函数与字符串ID相关联,以便Vue.js可以在模板中接收它. 了解了这点之后

  • 关于vue.extend和vue.component的区别浅析

    前言 最近一个朋友问我vue.extend和vue.component两者之间有什么区别?突然这么一问竟答不出来,回来想想有必要总结下,所以本文就来给大家介绍关于vue.extend和vue.component的区别,下面话不多说了,来一起看看详细的介绍吧. Vue.extend 返回的是一个"扩展实例构造器",也就是一个预设了部分选项的 Vue 实例构造器 var myVue = Vue.extend({ // 预设选项 }) // 返回一个"扩展实例构造器" /

  • vue.extend实现alert模态框弹窗组件

    本文通过Vue.extend创建组件构造器的方法写弹窗组件,供大家参考,具体内容如下 alert.js文件代码 import Vue from 'vue' // 创建组件构造器 const alertHonor = Vue.extend(require('./alert.vue')); var currentMsg = {callback:function(){ }} export default function(options){ var alertComponent = new alert

  • vue v-for 使用问题整理小结

    今天使用v-for指令的时候遇到一个错误 [Vue warn]: Error in render: "TypeError: Cannot read property 'children' of undefined" 页面使用代码 <template v-for="(c,i) in modelList.Course.children"> <div :key="i" class="course-block">

  • Vue中通过Vue.extend动态创建实例的方法

    在Vue中,如果我们想要动态地来控制一个组件的显示和隐藏,比如通过点击按钮显示一个对话框或者弹出一条信息.我们通常会提前写好这个组件,然后通过v-if = "show"来控制它的显示隐藏.如下所示: <div> <button @click = "show = !show">弹出</button> <span v-if = "show">这是一条通过按钮控制显示隐藏的信息</span>

随机推荐