在一个非单文件组件中(一个文件中包含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 则不同

Vue-extend和VueComponent相关推荐

  1. Vue.extend

    Vue.extend 1.传递的参数 Vue.extend({Object}),传递的是一个对象,这个对象包含template等,其实就是传递一个包含组件选项的对象. 他是属于Vue的全局API,用来 ...

  2. Vue利用Vue.extend()实现自定义弹出框

    运用场景:如果想实现一个类似于 window.alert() 提示组件要求像调用 JS 函数一样调用它,这时候Vue.extend + vm.$mount 组合就派上用场了. 简单介绍: Vue.ex ...

  3. vue.extend的问题

    问题场景 使用Vue.extend时 <template><div><div id="mount-point"></div>< ...

  4. V记录2(文档)Vue.extend构造器

    1.简单介绍 Vue.extend(options) 参数:对象 用法:使用Vue构造器,创建一个"子类",参数是一个包含组件选项的对象,其中,data选项中必须是函数 描述:Vu ...

  5. vue.extend与vue.component的区别和联系

    一味的闷头开发,却对基础概念缺乏理解,是个大坑... 查阅官网后现对自己的理解记录一下,用于日后复习巩固 Vue.extend({}) 简述:使用vue.extend返回一个子类构造函数,也就是预设部 ...

  6. Vue extend 学习

    <div id="box"><aa></aaa></div><script>var Aaa = Vue.extend({ ...

  7. vue2.0中组建里面套用组件_vue19 组建 Vue.extend component、组件模版、动态组件 的实例代码...

    具体代码如下所示: document var aaa=vue.extend({//继承出来一个vue类aaa template:' 我是标题3 ' }); var a=new aaa();//a跟vm ...

  8. Vue.extend构造器

    1.简单介绍 Vue.extend(options) 参数:对象 用法:使用Vue构造器,创建一个"子类",参数是一个包含组件选项的对象,其中,data选项中必须是函数 描述:Vu ...

  9. 关于vue.extend的理解应用

    一.基本概念 Vue.extend( options ) 使用基础 Vue 构造器,创建一个"子类".参数是一个包含组件选项的对象. 一般,我们会用 Vue.extend 接收一个 ...

  10. vue:extend和mixin的区别

    提到extend 总是感觉有些熟悉,都是可以共用一些方法和属性这不就是mixin混入吗?其实两者还是有较大差别的,可以类比后端语言的继承和多态,extend类似继承,而mixin类似多态. vue e ...

最新文章

  1. 【剑指offer】丑数
  2. ubuntu没有声音-只有类比立体声输入
  3. MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践 转载
  4. 一次项目测评反思:数据准备、测评要求和各种问题记录
  5. 这就是华为Mate 30 Pro真机了,价格或许要高攀不起了?
  6. php cookie注销,注销后未设置php cookie
  7. 用户体验报告(Echo)
  8. Ubuntu 安装 tensorflow-gpu 1.4 包含 CUDA 8.0 和cuDNN
  9. 硬盘扩容linux重新检查,Linux 无损扩容磁盘
  10. java实现,获取今日0时0分0秒(最小时间)-获取今日23时59分59秒(最大时间) -线程安全方法
  11. syslinux引导硬盘linux,使用SysLinux引导Linux系统
  12. 【寻找最佳小程序】影视评分小工具“豆瓣评分”——产品设计要点及专家评析...
  13. Visual Paradigm 里什么是复合结构图?
  14. 第十三届蓝桥杯复盘及未来规划
  15. WEB——Request与Response
  16. 使用 NumPy 来模拟随机游走(Random Walk)
  17. Kubernetes: kubectl 插件管理器 Krew 安装
  18. SSH三大框架面试题集锦
  19. 自己封装的文件服务苹果手机无法播放视频
  20. 微信机器人java-wechaty

热门文章

  1. c/c++刷题记录1(里面有我自己写的源码)
  2. STM32用SPI方式控制OLED模块
  3. 如何去掉裁剪图片的边框_裁剪框
  4. 项目集成短信验证功能(阿里云)详细实用教程
  5. java中operation用法,Java Operation.response方法代码示例
  6. Operation not permitted
  7. 在右键新建菜单中添加新项目
  8. 计算机组成原理试题(二)(附参考答案)
  9. 手动配置和自动配置ODBC数据源(C++)
  10. vue中使用a标签下载静态资源文件(比如excel、pdf等)后端不参与