IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue-extend和VueComponent -> 正文阅读

[JavaScript知识库]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 则不同

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 18:55:10  更:2022-08-19 18:58:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:46:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码