关于vue的详细笔记

Vue.js

Vue.js介绍

什么是Vue.js

简单小巧的核心,渐进式技术拢,足以应付任何规模的应用。 简单小巧是指 Vue.js 压缩后大小仅有 17kb。所谓渐进式(Progressive),就是你可以一步一 步、有阶段性地来使用 Vue.js,不必一开始就使用所有的东西。

MVVM模式

MVVM (Model-View-View Model)模式是由经典的软件架构 MVC 衍生来的。当 View (视图层)变化时,会自动更新到 ViewModel (视图模型),反之亦然。 View 和 ViewModel 之间通过双向绑定(tdata-binding)建立联系。

Vue.js有什么不同

Vue.js 通过 MVVM 的模式拆分为视图与数据两部分,并将其分离。因此,你只需要关心你 的数据即可, DOM 的事情 Vue 会帮你自动搞定。简单来讲,Vue.js就是数据驱动,利用数据来驱动视图,数据改变即可。

一个简单的Vue应用

Vue实例与数据绑定

Vue.js 应用的创建很简单,通过构造函数 Vue 就可以创建一个 Vue 的根实例,并启动 Vue 应
用:

var app =new Vue({ 
// 选项
el: document.getElementByld ('app')  // 或者是 '#app'
    data:{
        a:2
    }
})
  • el 用于指定一个页面中己存在的 DOM 元素来挂载 Vue 实例,它可以是 HTMLElement ,也可以是 css 选择器。

    挂载成功后,可以通过 app.$el 来访问该元素。

  • 通过 Vue 实例的 data 选项,可以声明应用内需要双向绑定的数据。

    Vue 实例本身也代理了 data 对象里的所有属性,所以可以这样访问:console . log (app. a)

生命周期

每个 Vue 实例创建时,都会经历一系列的初始化过程,同时也会调用相应的生命周期钩子, 我们可以利用这些钩子,在合适的时机执行我们的业务逻辑。

比较常见的有:

  • created 实例创建完成后调用,此阶段完成了数据的观测等,但尚未挂载, $el 还不可用。 需要初始化处理一些数据时会比较有用。
  • mounted el 挂载到实例上后调用,一般我们的第一个业务逻辑会在这里开始。
  • beforeDestroy 实例销毁之前调用。主要解绑一些使用 addEventListener 监听的事件等。

插值与表达式

  • 使用双大括号(Mustache 语法)"{ {}}"是最基本的文本插值方法,它会自动将我们双向绑定的数据实时显示出来。不过网速慢的时候,会有闪烁的情况出现。
<div id="app">
    {
   
   {book}}
</div> 

如果想显示{ {}}标签,而不进行替换, 使用 v-pre 即可跳过这个元素和它的子元素的编译过程。

<span v-pre>{
   
   {这里的内容是不会被编译的}}</span>

在插值表达式中,除了简单的绑定属性值外,还可以使用 JavaScript 表达式进行简单的运算、 三元运算等。Vue.js 只支持单个表达式,不支持语句和流控制。另外,在表达式中,不能使用用户自定义 的全局变量, 只能使用 Vue 白名单内的全局变量, 例如 Math 和 Date。

{
   
   { number / 10 }}
{
   
   { isOK ? '确定 ':'取消' }}
{
   
   { text.split (',').reverse().join(',') }}

  • 如果有的时候就是想输出 HTML,而不是将数据解释后的纯文本,可以使用 v-html:

如果将用户产生的内容使用 v-html 输出后,有可能导致 xss 攻击,所以要在服务端对用户提交的内容进行 处理, 一般可将尖括号"<>"转义。

<div id="app"> 
    <span v-html="link"></span> 
</div> 
  • 也可以使用 v-text,效果和差值表达式差不多,不过网速慢时,v-text不会有闪烁:
<div id="app"> 
    <span v-text="link"></span> 
</div> 

过滤器

Vue. 支持在{ {}}插值的尾部添加一小管道符 | 对数据进行过滤,经常用于格式化文 本,比如字母全部大写、货币千位使用逗号分隔等。过滤的规则是自定义的, 通过给 Vue 实例添加选项 filters 来设置。

// html
{
   
   { date | formatDate }}

// vm选项
filters : {
    // 这里的 value 就是需要过滤的数据
    formatDate : function (value) {
        
    }
}

过滤器也可以串联,而且可以接收参数,例如:

// 串联 
{
   
   { message | filterA | filterB }}
// 接收参数
{
   
   { message | filterA('arg1','arg2') }}

过滤器应当用于处理简单的文本转换,如果要实现更为复杂的数据变换,应该使用计算属性。

指令与事件

指令(Directives)是 Vue.js 模板中最常用的一项功能,它带有前缀 v-。指令的主要职责就是当其表达式的值改变时,相应地 将某些行为应用到 DOM 上(数据驱动DOM)。

基础使用:

  • v-bind:可以动态更新HTML元素上的属性(简写:)。
  • v-on:绑定事件监听器(简写@)。

    Vue.js将 methods 里的方法也代理了,所以也可以像访问 Vue 数据那样来调用方法:

计算属性

什么是计算属性

插值表达式里的表达式如果过长,或逻辑更为复杂时,就会变得雕肿甚至难以阅读和维护,所以在遇到复杂的逻辑时应该使用计算属性。

// 之前
{
   
   { text.split(',').reverse().join(',') }} 

// 使用计算属性后
{
   
   { reversedText }} 
<script> 
var app =new Vue({ 
    el :'#app', 
    data:{ 
        text:'123,456',
    }
    computed:{
        reversedText: function () { 
            //这里的 this 指向的是当前的 Vue 实例 
            return this.text.split(',').reverse().join(','); 
        }
    }
})
</script> 

所有的计算属性都以函数的形式写在 Vue 实例内的 computed 选项内,最终返回计算后的结果。

计算属性用法

  • 在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。除了上例简单的用法,计算属性还可以依赖多个 Vue 实例的数据,只要其中任一数据 变化,计算属性就会重新执行,视图也会更新。

  • 每一个计算属性都包含一个 getter 和一个 setter,计算属性的默认用法为getter。在你需要时,也可以提供一个 setter 函数, 当手动修改计算属性的 值就像修改一个普通数据那样时,就会触发 setter 函数,执行一些自定义的操作,

计算属性可以依赖其他计算属性。同时计算属性不能携带参数,如果非要带入参数,需要使用闭包。

计算属性缓存

调用methods 里的方法也可以与计算属性起到同样的作用,甚至调用methods还可以灵活携带参数,为什么不使用调用methods呢?

计算属性是基于它的依赖缓存的,一个计算属性所依赖的数据发生变化时,它才会重新取值。

使用计算属性还是 methods 取决于你是否需要缓存,当遍历大数组和做大量计算时,应当使用 计算属性,除非你不希望得到缓存。

v-bind及class与style绑定

绑定class的几种方式

  • 对象语法

给 v-bind:class 设置一个对象,可以动态地切换 class,例如:

<div id="app">
    // isActive为data里的数据(true或者false)
    <div :class="{'active': isActive }"></div> 
</div> 

当:class 的表达式过长或逻辑复杂时,还可以绑定一个计算属性,这是一种很友好和常见的用法,一般当条件多于两个时,都可以使用 data 或 computed,都是返回一个Object。

  • 数组语法

当需要应用多个 class 时, 可以使用数组语法, 给:class 绑定一个数组,应用一个 class 列表:

<div id="app">
    <div :class="[activeCls, errorCls]"></div>
</div> 

也可以使用三元表达式来根据条件切换 class:

<div id="app">
    // isActive为boolean值
    <div :class="[isActive ? activeCls : '', errorCls]"></div> 
</div>

class 有多个条件时, 这样写较为烦琐,可以在数组语法中使用对象语法:

<div id="app"> 
    // isActive为boolean值
    <div :class="[{ 'active': isActive }, errorCls]"></div> 
</div> 

与对象语法一样,也可以使用 data、 computed 和 methods 三种方法

  • 在组件上使用

    如果直接在自定义组件上使用 class 或 :class,样式规则会直接应用到这个组件的根元素上.

绑定内联样式

使用 v-bind:style (即:style) 可以给元素绑定内联样式,方法与:class 类似,也有对象语法和 数组语法,看起来很像直接在元素上写 CSS:

<div id="app"> 
    <div :style="{ 'color': 'red', 'fontSize': 14 + 'px' }">文本</div>
</div>

css 属性名称使用驼峰命名(camelCase)或短横分隔命名(kebab-case),大多数情况下, 直接写一长串 的样式不便于阅读和维护,所以一般写在 data 或 computed 里。

应用多个样式对象时, 可以使用数组语法:

<div :style="[styleA, styleB]">文本</div>

在实际业务中,:style 的数组语法并不常用, 因为往往可以写在一个对象里面: 而较为常用的应当是计算属性。

内置指令

基本指令

  • v-cloak

    v-cloak 不需要表达式,它会在 Vue 实例结束编译时从绑定的 HTML 元素上移除, 经常和 css 的 display: none;配合使用:

    <div id="app" v-cloak> {
         
         {message}} </div>
    
    [v-cloak] { 
        display: none; 
    }
    
  • v-once

    v-once 也是一个不需要表达式的指令,作用是定义它的元素或组件只渲染一次,包括元素或 组件的所有子节点。首次渲染后,不再随数据的变化重新渲染,将被视为静态内容,

    v-once 在业务中也很少使用,当你需要进一步优化性能时,可能会用到。

条件渲染指令

  • v-if、 v-else-if、 v-else

    与 JavaScript 的条件语句 if else、 else if类似, Vue.js 的条件指令可以根据表达式的值在 DOM 中渲染或销毁元素/组件。

    <p v-if="status === 1">status 为 1 时显示该行</p> 
    <p v-else-if="status === 2">status 为 2 时显示该行</p> 
    <p v-else>否则显示该行</p>
    

    v-else-if 要紧跟 v-if, v-else 要紧跟 v-else-if 或 v-if,表达式的值为真时, 当前元素/组件及所 有子节点将被渲染,为假时被移除。

    如果一次判断的是多个元素,可以在 Vue.js 内置的 元素上使用条件指令,最终渲染的结果不会包含该元素。

    <template v-if="status === 1"> 
        <p>这是一段文本</p> 
        <p>这是一段文本</p> 
        <p>这是一段文本</p>
    </template> 
    

    Vue 在渲染元素时,出于效率考虑,会尽可能地复用已有的元素而非重新渲染。简单来说,就是使用v-if、v-else-if、v-else,元素可能会就地复用(input上面的值会保留)。如果不希望这样做,可以使用 Vue.js 提供的 key 属性,它可以让你自己决定是否要复用元素, key 的值必须是唯一的。

  • v-show

    v-show 的用法与 v-if基本一致,只不过 v-show 是改变元素的 css 属性 display。当 v-show 表 达式的值为 false 时, 元素会隐藏,查看 DOM 结构会看到元素上加载了内联样式 display: none;。

    v-show不能在上使用

  • v-if 与 v-show 的选择

    v-if和 v-show 具有类似的功能,不过 v-if 才是真正的条件渲染,它会根据表达式适当地销毁 或重建元素及绑定的事件或子组件。若表达式初始值为 false,则一开始元素/组件并不会渲染,只 有当条件第一次变为真时才开始编译。而 v-show 只是简单的 css 属性切换,无论条件真与否,都会被编译。相比之下, v-if更适合 条件不经常改变的场景,因为它切换开销相对较大,而 v-show 适用于频繁切换条件。

列表渲染指令 v-for

基本用法

当需要将一个数组遍历或枚举一个对象循环显示时,就会用到列表渲染指令 v-for

<li v-for="book in books">{
   
   { book.name }}</li> 

列表渲染也支持用 of 来代替 in 作为分隔符

v-for 的表达式支持一个可选参数作为当前项的索引,例如:

<li v-for="(book, index) in books">{
   
   { index }} - {
   
   { book })</li> 

与 v-if一样, v-for 也可以用在内置标签<template>上, 将多个元素进行渲染:

<template v- for="book in books">
    <li>书名:{
   
   { book.name }}</li>
    <li>作者:{
   
   { book.author }}</li>
</template> 

除了数组外, 对象的属性也是可以遍历的,使用方法如同数组,不过,遍历对象属性时,有两个可选参数,分别是键名和索引。例如:

<li v-for= "(value, key, index) in user"> {
   
   { index }} - {
   
   { key }} : {
   
   { value }} 
</li>

数组更新

Vue 的核心是数据与视图的双向绑定,当我们修改数组时, Vue 会检测到数据变化,所以用 v-for 渲染的视图也会立即更新。 Vue 包含了一组观察数组变异的方法,使用它们改变数组也会触发视图更新:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

因为上述方法会改变原数组,如果要使用其他数组方法,要用新数组来替换原数组。Vue 在检测到数组变化时,并不是直接重新渲染整个列表,而是最大化地复用 DOM 元素。替换的数组中,含有相同元素的项不会被重新渲染,因此可以大胆地用新数组来替换旧数组,不用担心性能问题。

需要注意的是,以下变动的数组中, Vue 是不能检测到的,也不会触发视图更新:

  • 通过索引直接设置项,比如 app.books[3] = { … }。
  • 修改数组长度,比如app.books.length = 1。

如果非要这样做,可以使用set或者$set方法

// 使用 Vue 内置的 set 方法
Vue.set(app.books, 3, {});
// 在 webpack 中使用组件化的方式,默认是没有导入 Vue 的,这时可以使用$set 
this.$set(app.books, 3, {});

过滤与排序

当你不想改变原数组,想通过一个数组的副本来做过滤或排序的显示时,可以使用计算属性 来返回过滤或排序后的数组。例如:

<template v-for="book in filterBooks"> 
    <li>书名: {
   
   { book.name }}</li> 
    <li>作者: {
   
   { book.author }}</li> 
</template>
computed: { 
    filterBooks: function () {}
} 

方法与事件

基本用法

绑定事件一般使用:v-on,例如:@click。@click 的表达式可以直接使用 JavaScript 语句,也可以是一个在 Vue 实例中 methods 选项内 的函数名。

需要注意的是,@click 调用的方法名后 可以不跟括号“()” 。此时,如果下面该方法有参数,默认会将原生事件对象 event 传入。

Vue 还提供了一个特殊变量$event,用于访问原生 DOM 事件。

<a href="http://www.apple.com" @click="handleClick('禁止打开',$event)">打开链接</a>
handleClick: function (message, event) { 
    // 阻止默认行为
    event.preventDefault() ; 
    window.alert(message); 
}

表单与v-model

基本用法

表单控件在实际业务较为常见,比如单选、多选、下拉选择、输入框等,用它们可以完成数据的录入、校验、提交等。 Vue.js 提供了 v-model 指令,用于在表单类元素上双向绑定数据。

使用 v-model 后,表单控件显示的值只依赖所绑定的数据,不再关心初始化时的 value 属性,对于在 之间插入的值,也不会生效. 使用 v-model 时,如果是用中文输入法输入中文,一般在没有选定词组前,也就是在 拼音阶段, Vue 是不会更新数据的,当敲下汉字时才会触发更新。如果希望总是实时更新,可以用@input 来替代 v-model。

单选按钮

单选按钮在单独使用时,不需要 v-model,直接使用 v-bind 绑定一个布尔类型的值, 为真时 选中, 为否时不选。

<!--picked为布尔值。radio选中后,再次点击是不会取消选中的-->
<input type="radio" :checked="picked"> 

如果是组合使用来实现互斥选择的效果,就需要 v-model 配合 value 来使用:

<!--数据 picked 的值与单选按钮的 value 值一致时,就会选中该项。相反,选中的元素,picked的值和value值一致-->
<input type="radio" v-model="picked" value="html" id="html">
<label for="html">HTML</label>
<br>
<input type="radio" v-model="picked" value="js" id="js">
<label for="js">JavaScript</label > 

复选按钮

复选框单独使用时,也是用 v-model 来绑定一个布尔值

<!--checked为boolean值。checkbox选中后,再次点击是会取消选中的-->
<input type="checkbox" v-model="checked" id="checked"> 

组合使用时,也是 v-model 与 value 一起,多个勾选框都绑定到同一个数组类型的数据, value 的值在数组当中,就会选中这一项。这一过程也是双向的,在勾选时, value 的值也会自动 push 到 这个数组中。

<!--值得注意的是:checked在这里是个数组-->
<input type="checkbox" v-model="checked" value="html" id="html">
<label for="html">HTML</label> 
<br> 
<input type="checkbox" v-model="checked" value="js" id="js">
<label for="js">JavaScript</label> 

选择列表(下拉选择器)

选择列表就是下拉选择器,也是常见的表单控件,同样也分为单选和多选两种方式。

<select v-model="selected"> 
    <option>html</option> 
    <option value="js">JavaScript</option>
    <option>css</option> 
</select> 
是备选项,如果含有 value 属性, v-model 就会优先匹配 value 的值: 如果没有,就会直接匹配的 text,比如选中第二项时, selected 的值是js, 而不是 JavaScript。

给添加属性 multiple 就可以多选了,此时 v-model 绑定的是一个数组。

绑定值

上面介绍的单选按钮、复选框和选择列表在单独使用或单选的模式下, v-model 绑定的值是一 个静态字符串或布尔值(固定的几个值), 但在业务中,有时需要绑定一个动态的数据, 这时可以用 v-bind 来实现。

单选按钮

<input type="radio" v-model="picked" :value="value"> 

勾选时,app.toggle === app.value1;未勾选时,app.toggle === app.value2。

复选框

<input type="checkbox" v-model="toggle" :true- value="valuel" :false-value="value2"> 

勾选时, app.toggle === app.valuel; 未勾选时, app.toggle === app.value2。

选择列表

<select v-model="selected"> 
    <option :value="{ number:123 }">123</option> 
</select> 

当选中时, app.selected 是一个 Object,所以 app.selected.number == 123。

修饰符

修饰符可以连用,顺序从左到右。

表单修饰符

  • .lazy

在输入框中, v-model 默认是在 input 事件中同步输入框的数据(除了提示中介绍的中文输入法情况外),使用修饰符 .lazy 会转变为在 change 事件中同步。

<input type="text" v-model.lazy="message"> 
<!--这时,message 并不是实时改变的,而是在失焦或按回车时才更新-->
<p>{
   
   { message }}</p> 
  • .trim

修饰符 .trim 可以自动过滤输入的首尾空格

  • .number

使用修饰符.number 可以将输入转换为 Number 类型。如果你先输入数字,那它就会限制你输入的只能是数字。如果你先输入字符串,那它就相当于没有加.number

事件修饰符

  • .stop

一键阻止事件冒泡,相当于调用了event.stopPropagation()方法。

  • .prevent

用于阻止事件的默认行为,相当于调用了event.preventDefault()方法。

  • .self

只当事件是从事件绑定的元素本身触发时才触发回调。

  • .once

事件只会被触发一次

  • .capture

事件机制变为捕获

  • .passive

相当于给onscroll事件整了一个.lazy修饰符

  • .native

该修饰符的作用就是把一个vue组件转化为一个普通的HTML标签,使得普通事件能够作用在组件上

鼠标修饰符

我们一般是会用左键触发,有时候我们需要更改右键菜单啥的,就需要用到右键点击或者中间键点击,这个时候就要用到鼠标按钮修饰符。

  • .left

左键点击

  • .right

右键点击

  • .middle

中键点击

按键修饰符

普通键

  • .enter
  • .tab
  • .delete

捕获“删除”和“退格”键

  • .space
  • .esc
  • .up
  • .down
  • .left
  • .right

系统修饰键

  • .ctrl
  • .alt
  • .meta
  • .shift
<!-- 实例 -->
<input type="text" @keyup.enter="shout(4)">
// 通过全局 config.keyCodes 对象自定义按键修饰符别名:
Vue.config.keyCodes.f1 = 112

键分成了普通常用的键和系统修饰键,区别在于:系统修饰键是无法单独触发keyup事件的,我们需要将系统修饰键和其他键码链接起来使用,比如:

<!-- 这样当我们同时按下ctrl+c时,就会触发keyup事件 -->
<input type="text" @keyup.ctrl.67="shout(4)">

如果是鼠标事件,那就可以单独使用系统修饰符。

<button @mouseover.ctrl="shout(1)">ok</button>
<button @mousedown.ctrl="shout(1)">ok</button>
<button @click.ctrl.67="shout(1)">ok</button>

.exact(2.5 新增)

当我们只需要按下一个系统修饰键时,同时按下几个系统修饰键,比如ctrl shift点击,也能触发我们想要触发的事件。而 .exact 就是精确地来控制系统修饰键的个数。

注意:这个只是限制系统修饰键的。

<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>

v-bind修饰符

.sync

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。.sync 就是快速帮助我们完成这些事情。

// 父亲组件
<comp :myMessage="bar" @update:myMessage="func"></comp>
//js
func(e){
 this.bar = e;
}

// 子组件js
func2(){
  this.$emit('update:myMessage',params);
}

现在这个.sync修饰符就是简化了上面的步骤

//父组件
<comp :myMessage.sync="bar"></comp>
//子组件
this.$emit('update:myMessage',params);

注意:

  1. 使用sync的时候,子组件传递的事件名必须为update:value,其中value必须与子组件中props中声明的名称完全一致(如上例中的myMessage,不能使用my-message)
  2. 注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的属性名,类似 v-model。
  3. 将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。

.prop

首先要搞懂 Property 和 Attribute 的区别。

  • Property:javascript获取到的DOM节点对象。节点对象在内存中存储的属性,可以访问和设置。
  • Attribute:节点对象的其中一个属性( property ),值是一个对象。它是HTML标签上的某个属性,值只能是字符串。

可以通过点访问法 document.getElementById(‘xx’).attributes 或者 document.getElementById(‘xx’).getAttributes(‘xx’) 读取,通过 document.getElementById(‘xx’).setAttribute(‘xx’,value) 新增和修改。
在标签里定义的所有属性包括 HTML 属性和自定义属性都会在 attributes 对象里以键值对的方式存在。

其实attribute和property两个单词,翻译出来都是属性,但是《javascript高级程序设计》将它们翻译为特性和属性,以示区分

// 这里的id,value,style都属于property
// index属于attribute
// id、title等既是属性,也是特性。修改属性,其对应的特性会发生改变;修改特性,属性也会改变
<input id="uid" title="title1" value="1" :index="index">
// input.index === undefined
// input.attributes.index === this.index

从上面我们可以看到如果直接使用v-bind绑定,默认会绑定到dom节点的attribute。而使用了 .prop 会将数据绑定在 Property 中。
为了:

  • 通过自定义属性存储变量,避免暴露数据
  • 防止污染 HTML 结构

我们可以使用这个修饰符,如下

<input id="uid" title="title1" value="1" :index.prop="index">
//input.index === this.index
//input.attributes.index === undefined

.camel

由于HTML 特性是不区分大小写的。

<svg :viewBox="viewBox"></svg>
<!--实际上会渲染为-->
<svg viewbox="viewBox"></svg>

这将导致渲染失败,因为 SVG 标签只认 viewBox,却不知道 viewbox 是什么。
如果我们使用.camel修饰符,那它就会被渲染为驼峰名。

但是,我们平常都是使用字符串模板或通过 vue-loader/vueify 编译,所以这个修饰符一般修饰符用不上的。

组件详解

组件与复用

在项目中统一样式,并且提高复用性,方便后期修改。

组件需要注册后才可以使用。注册有全局注册和局部注册两种方式。全局注册后, 任何 Vue 实例都可以使用。

全局注册

Vue.component("my-component", { 
    // 选项
    // template的 DOM 结构必须被一个元素包含
    template: '<div>这里是组件的内容</div>',
    data:function(){
        return {
            message: '组件内容'
        }
    }
})

my-component 就是注册的组件自定义标签名称,推荐使用小写加减号分割的形式命名。 要在父实例中使用这个组件,必须要在实例创建前注册,之后就可以用的形式来使用组件了。

除了 template 选项外,组件中还可以像 Vue 实例那样使用其他的选项,比如 data、 computed、 methods 等。但是在使用 data 时, 和实例稍有区别, data 必须是函数,然后将数据 return 出去(防止数据共享)。

局部注册

使用 components 选项可以局部注册组件,注册后的组件只有在该实例作用域 下有效。组件中也可以使用 components 选项来注册组件,使组件可以嵌套。

<div id="app">
    <my-component></my-component> 
</div> 
var Child = { template : '<div>局部注册组件的内容</div>' };
var app =new Vue({ 
    el:'#app',
    components:{ 
        'my-component':Child
    }
})

组件限制

Vue 组件的模板在某些情况下会受到 HTML 的限制,比如<table>内规定只允许是<tr>、<td>、 <th>等这些表格元素,所以在<table>内直接使用组件是无效的。 这种情况下,可以使用特殊的 is 属性来挂载组件。

<div id="app">
    <table> 
        <tbody is="my-component"></tbody> 
    </table> 
</div> 
Vue.component ('my-component',{
    template:'<div>这里是组件的内容</div>'
});
var app =new Vue({ 
    el: '#app' 
}) 

使用props传递数据(父向子通信)

在组件中,使用选项 props 来声明需要从父级接收的数据, props 的值可以是两种, 一种是字符串数组,一种是对象。

由于 HTML 特性不区分大小写,当使用 DOM 模板时,驼峰命名 (camelCase)的 props 名称要转为短横分隔命名 (kebab-case)。

一般我们都不会直接去操作props里的数据。要么我们使用一个data里的变量保存,要么直接使用计算属性。注意:如果props数据为数组或者对象,修改子组件的数据,父组件的数据也会跟着改变,故不推荐直接操作props里的数据。

字符串数组

<div id="app">
    <input type="text" v-model="parentMessage">
    <my-component :message="parentMessage"></my-component>
</div>
Vue.component('my-component',{ 
    props: ['message'], 
    template:'<div>{
   
   { message }}</div>'
});
var app = new Vue ({ 
    el:'#app',
    data: { 
        parentMessage:''
    }
}); 

对象(数据验证)

props 选项的值,除了数组外,还可以是对象,当 prop 需要验证时,就需要对象写法。

props : { 
    // 必须是数字类型 
    propA: Number, 
    // 必须是字符串或数字类型 
    propB : [String, Number] , 
    // 布尔值,如果没有定义,默认值就是 true 
    propC: { 
        type : Boolean, 
        default : true
    }
    // 数字,而且是必传 
    propD: { 
        type: Number, 
        required: true
    }
    // 如果是数组或对象,默认值必须是一个函数来返回
    propE: { 
        type : Array, 
        default : function () { 
            return [];
        }
    }
    // 自定义一个验证函数 
    propF: { 
        validator: function (value) { 
            return value > 10;
        }
    }
}

组件通信

组件关系可分为父子组件通信、兄弟组件通信、跨级组件通信。

自定义事件(子向父通信)

子组件用 e m i t ( ) 来 触 发 事 件 , 父 组 件 用 emit()来触发事件,父组件用 emit()on()来监昕子组件的事件,父组件也可以直萨在子组件的自定义标签上使用 v-on 来监昕子组件触发的自定义事件。

<div id="app">
    <p>总数: {
   
   { total }}</p>
    <my-component @increase="handleGetTotal" @reduce="handleGetTotal"></my-component> 
</div>
Vue.component ('my-component', { 
    template:`
    <div>
        <button @click='handleIncrease'>+1</button>
        <button @click= 'handleReduce'>-1</button>
    </div>`,
    data : function () { 
        return { 
            counter: 0
        }
    },
    methods : { 
        handleincrease: function () {
            this.counter++;
            this.$emit('increase', this.counter); 
        },
        handleReduce: function () {
            this.counter--;
            this.$emit('reduce', this.counter);
        }
    }
});

var app =new Vue({ 
    el: '#app',
    data: { 
        total: 0 
    },
    methods: { 
        handleGetTotal: function (total) { 
            this.total = total;
        }
    }
}); 

使用v-model

Vue2.x 可以在自定义组件上使用 v-model 指令

<div id="app">
    <p>总数:{
   
   { total }}</p>
    <my-component v-model="total"></my-component> 
</div> 
Vue.component('my-component',{ 
    template: '<button @click=”handleClick”>+l</button>',
    data: function () { 
        return { 
            counter: 0 
        }
    },
    methods : { 
        handleClick: function () {
            this.counter++; 
            this.$emit('input', this.counter);
        }
    }
});

var app = new Vue({ 
    el: '#app',
    data: { 
        total: 0 
    }
});

这次组件$emit()的事件名是特殊的 input, 在使用组件的父 级,井没有在上使用@input= “handler”,而是直接用了 v-model 绑定的一个数据 total。这也可以称作是一个语法糖,因为上面的示例可以间接地用自定义事件来实现。

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的。model 选项可以用来避免这样的冲突:

model: {
    prop: 'checked',
    event: 'change'
}
// ....
this.$emit('change', this.checked);

v-model 通信双向绑定

<div id="app">
    <p>总数: {
   
   { total }}</p>
    <my-component v-model="total"></my- component>
    <button @click="handleReduce">- 1</button>
</div>
Vue.component('my-component',{ 
    props: ['value'],
    template: '<input :value="value" @input="updateValue">',
    methods : { 
        updateValue: function (event) {
            this.$emit('input', event.target.value);
        }
    }
});

var app = new Vue({ 
    el: '#app',
    data: { 
        total: 0 
    },
    methods: {
        handleReduce : function () {
            this.total--; 
        } 
    }
});

实现这样一个具有双向绑定的 v-model 组件要满足下面两个要求:

  • 接收一个value属性。
  • 在有新的value时触发input事件。

非父子组件通信

在实际业务中,除了父子组件通信外,还有很多非父子组件通信的场景,非父子组件一般有 两种,兄弟组件和跨多级组件。

在Vue.js l.x 中,除了 e m i t ( ) 方 法 外 , 还 提 供 了 emit()方法外,还提供了 emit()dispatch()和 b r o a d c a s t ( ) 这 两 个 方 法 。 broadcast()这两个方法。 broadcast()dispatch()用于向上级派发事件,只要是它的父级(一级或多级以上〉,都可以在 Vue 实例的 events 选项内接收。同理, $broadcast()是由上级向下级广播事件的,用法完全一致。

在 Vue.2.x 中 ,推荐使用一个空的 Vue 实例作为中央事件总线(bus),也就是一个中介。

<div id="app">
    {
   
   { message }}
    <component-a></component-a>
</div>
var bus= new Vue (); 

Vue.component ('component-a', {
    template: '<button @click="handleEvent">传递事件</button>',
    methods: {
        handleEvent: function () {
            bus.$emit('on-message', '来自组件 component-a 的内容');
        }
    }
});

var app =new Vue ({ 
    el: '#app',
    data: { 
        message:  '' 
    },
    mounted: function () { 
        var _this = this; 
        // 在实例初始化时,监听来自 bus 实例的事件 
        bus.$on('on-message', function (msg) {
            _this.message = msg;
        });
    }
});

父链

在子组件中,使用 this. p a r e n t 可 以 直 接 访 问 该 组 件 的 父 实 例 或 组 件 , 父 组 件 也 可 以 通 过 t h i s . parent 可以直接访问该组件的父实例或组件,父组件也可以通过 this. parent访this.children 访问它所有的子组件,而且可以递归向上或向下无限访问,直到根实例或最内层的组件。

<div id="app">
    {
   
   { message }}
    <component-a></component-a>
</div>
Vue.component ('component-a', {
    template: '<button @click="handleEvent">通过父链直接修改数据</button>',
    methods: {
        handleEvent: function () {
            // 访问到父链后,可以做任何操作,比如直接修改数据 
            this.$parent.message = '来自组件 component-a 的内容';
        }
    }
});

var app =new Vue ({ 
    el: '#app',
    data: { 
        message:  '' 
    }
});

尽管 Vue 允许这样操作,但在业务中,子组件应该尽可能地避免依赖父组件的数据,更不应该去主动修改它的数据,因为这样使得父子组件紧藕合,只看父组件,很难理解父组件的状态,因为它可能被任意组件修改,理想情况下,只有组件自己能修改它的状态。父子组件最好还是通过 props 和$emit 来通信。一般更多的时候,是去调用父组件的方法,而不是去修改父组件的东西。

子组件索引

当子组件较多时,通过 this.$children 来一一遍历出我们需要的一个组件实例是比较困难的, 尤其是组件动态渲染时,它们的序列是不固定的。Vue 提供了子组件索引的方法,用特殊的属性 ref 来为子组件指定一个索引名称。

<div id="app">
    <button @click="handleRef">通过 ref 获取子组件实例</button>
    <component-a ref="comA"></component-a>
</div> 
Vue.component ('component-a', {
    template: '<div>子组件</div>',
    data: function() {
        return { 
            message: '子组件内容'
        }
    }
});

var app = new Vue ({ 
    el:'#app',
    methods: { 
        handleRef: function () { 
            // 通过 $refs 来访问指定的实例 
            var msg = this.$refs.comA.message;
            console.log(msg); 
        }
    }    
}); 

在父组件模板中,子组件标签上使用 ref指定一个名称,井在父组件内通过 this.$refs 来访问指定名称的子组件。 Vue 会自动去判断是普通标签还是组件。

r e f s 只 在 组 件 渲 染 完 成 后 才 填 充 , 并 且 它 是 非 响 应 式 的 , 它 仅 仅 作 为 一 个 直 接 访 问 子 组 件 的 应 急 方 案 , 应 当 避 免 在 模 板 或 计 算 属 性 中 使 用 refs只在组件渲染完成后才填充,并且它是非响应式的,它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用 refs访使refs。

使用 slot 分发内容

当需要让组件组合使用,混合父组件的内容与子组件的模板时,就会用到 slot, 这个过程叫作 内容分发(transclusion)。

slot 用法

在子组件内使用特殊的元素就可以为这个子组件开启一个 slot (插槽),在父组件模板里,插入在子组件标签内的所有内容将替代子组件的 标签及它的内容。

<div id="app">
    <child-component> 
        <p>分发的内容</p> 
        <p>更多分发的内容</p>
    </child-component>
</div>
// 注意,子组件<slot>内的备用内容,它的作用域是子组件本身.
Vue.component('child-component', { 
    template:`
    <div>
        <slot> 
            <p>如果父组件没有插入内容,我将作为默认出现</p>
        </slot>
    </div>`
});

var app = new Vue({
    el: '#app'
});

子组件 child-component 的模板内定义了一个元素,并且用一个< p>作为默认的内容, 在父组件没有使用 slot 时,会渲染这段默认的文本;如果写入了 slot, 那就会替换整个 。所以上例渲染后的结果为:

<div id="app">
    <div> 
        <p>分发的内容</p>
        <p>更多分发的内容</p>
    </div> 
</div>

具名 Slot

给元素指定一个 name 后可以分发多个内容,具名 Slot 可以与单个 Slot 共存。

<div id="app"> 
    <child-component> 
        <h2 slot="header">标题</h2> 
        <p>正文内容</p>
        <p>更多的正文内容</p>
        <div slot="footer">底部信息</div> 
    </child-component> 
</div> 
Vue.component ('child-component', {
    template:`
        <div class="container">
            <div class="header"> 
                <slot name="header"></slot>
            </div> 
            <div class="main"> 
                <slot></slot>
            </div>
            <div class="footer">
                <slot name="footer"></slot> 
            </div> 
        </div>`
});

var app =new Vue({ 
    el: '#app'
});

子组件内声明了 3 个<slot>元素,其中在<div class=”main与内的<slot> 没有使用 name 特性, 它将作为默认 slot 出现,父组件没有使用 slot 特性的元素与内容都将出现在这里。 所以上例渲染后的结果为:

<div id="app">
    <div class="container">
        <div class="header"> 
            <h2>标题</h2>
        </div> 
        <div class="main">
            <p>正文内容</p> 
            <p>更多的正文内容</p>
        </div> 
        <div class="footer"> 
            <div>底部信息</div>
        </div>
    </div>
</div> 

作用域插槽

作用域插槽是一种特殊的 slot,使用一个可以复用的模板替换己渲染元素。

<div id="app">
    <child-component> 
        <template scope="props">
            <p>来组父组件的内容</p>
            <p>{
   
   { props.msg }}</p> 
        </template> 
    </child-component>
</div>
Vue.component('child-component' , {
    template: `
    <div class="container">
        <slot msg="来自子组件的内容"></slot>
    </div> ` 
});

var app = new Vue ({ 
    el: '#app' 
});

观察子组件的模板,在元素上有一个类似 props 传递数据给组件的写法 msg=”xxx”,将数据传到了插槽。父组件中使用了元素,而且拥有一个 scope=”props”的特性,这里的 props 只是一个临时变量,就像 v-for=”item in items”里面的 item 一样。template 内可以通过临时变量 props 访问来自子组件插槽的数据 msg。

<div id="app">
    <div class="container">
        <p>来组父组件的内容</p>
        <p>来自子组件的内容</p>
    </div> 
</div> 

访问 slot

Vue.js 2.x 提供 了用来访问被 slot 分发的内容的方法 $slots。

<div id="app">
    <child-component>
        <h2 slot="header">标题</h2>
        <p>正文内容</p>
        <p>更多的正文内容</p>
        <div slot="footer">底部信息</div>
    </child-component> 
</div> 
Vue.component('child-component', {
    template: ` 
    <div class="container">
        <div class="header"> 
            <slot name="header"></slot> 
        </div> 
        <div class="main">
            <slot></slot> 
        </div> 
        <div class="footer"> 
            <slot name="footer"></slot>
        </div>
    </div>`, 
    mounted: function () { 
        var header = this.$slots.header;
        var main = this.$slots.default;
        var footer = this.$slots.footer;
        console.log(footer);
        console.log(footer[0].elm.innerHTML);
    } 
});

var app =new Vue({ 
    el: '#app' 
});

通过 s l o t s 可 以 访 问 某 个 具 名 s l o t , t h i s . slots 可以访问某个具名 slot, this. slots访slot,this.slots.default 包括了所有没有被包含在具名 slot 中的节点。尝试编写代码,查看两个 console 打印的内容。

2.6 以后更换语法

在 Vue 2.6 版本之后,将 slot 与 scope-slot 语法进行了合并。

slot 语法更名为v-slot,简写#。且 v-slot只能写在 template 标签上。

// 组件调用时
<MyFooter>
  <template v-slot:footer>
        // 这里v-slot:后边的值与组件内的slot的name属性对应,也就是插槽的名称。
        <div>list</div>
  </template>
</MyFooter>
// 书写组件时
<template>
    <div>
        <div>
            // 这里name的值就是这个插槽的名称。
            <slot name='footer'/>
        </div>
    </div>
</template>

作用域插槽写法将更加精简。

作用域插槽的主要作用是在书写插槽内容时可以获取到插槽作用域的值。需要注意的是message是所有你绑定属性的集合。

// 组件调用
 <ul>
   <myli :title="val.title">
        <template v-slot:footer="message">
            <div>{
   
   {message.aa}}</div>
        </template>
   </myli>
 </ul>
 // 书写组件时
 <template>
    <li>
        <slot name='footer' :aa="title"></slot>
    </li>
</template>

组件高级用法

递归组件

组件在它的模板内可以递归地调用自己,只要给组件设置 name 的选项就可以了。

<div id="app">
    <child-component: count="1"></child-component> 
</div> 
Vue.component('child-component', {
    name: 'child-component', 
    props: {
        count: {
            type: Number,
            default: 1
        }
    },
    template: ` 
    <div class="child">
       <child-component :count="count + 1"  v-if="count < 3"></child-component>
    </div>`
});

var app =new Vue({ 
    el: '#app' 
});

设置 name 后,在组件模板内就可以递归使用了,不过需要注意的是,必须给一个条件来限制递归数量,否则会抛出错误: max stack size exceeded。组件递归使用可以用来开发一些具有未知层级关系的独立组件,比如级联选择器和树形控件等。

内联模板

组件的模板一般都是在 template 选项内定义的, Vue 提供了一个内联模板的功能,在使用组件时,给组件标签使用 inline-template 特性,组件就会把它的内容当作模板,而不是把它当内容分发,这让模板更灵活。

<div id= "app">
    <child-component inline-template> 
        <div> 
            <h2>在父组件中定义子组件的模板</h2> 
            <p>{
   
   { message }}</p> 
            <p>{
   
   { msg }}</p> 
        </div>
    </child-component> 
</div>
Vue.component ('child-component', {
    data: function () { 
        return { 
            msg: '在子组件声明的数据'
        }
    }
});

var app =new Vue ({
    el: '#app',
    data: {
        message: '在父组件声明的数据'
    }
});

在父组件中声明的数据 message 和子组件中声明的数据 msg, 两个都可以渲染(如果同名,优先使用子组件的数据)。

<div id="app">
    <div> 
        <h2>在父组件中定义子组件的模板</h2>
        <p>在父组件声明的数据</p>
        <p>在子组件声明的数据</p>
    </div> 
</div>

动态组件

Vue.js 提供了一个特殊的元素 用来动态地挂载不同的组件,使用 is 特性来选择要挂载的组件。

<div id="app">
    <component :is="currentView"></component> 
    <button @click="handleChangeView('A')">切换到 A</button>
    <button @click="handleChangeView('B')">切换到 B</button>
    <button @click="handleChangeView('c')">切换到 C</button>
</div> 
var app =new Vue({ 
    el: '#app',
    components: { 
        comA: { 
            template: '<div>组件 A</div>'
        },
        comB: { 
            template:'<div>组件 B</div>'
        },
        comC: { 
            template: '<div>组件 C</div>'
        }
    },
    data: { 
        currentView: 'comA'
    },
    methods: { 
        handleChangeView: function (component) { 
            this.currentView = 'com' + component; 
        }
    }
});

动态地改变 currentView 的值就可以动态挂载组件了。也可以直接绑定在组件对象上:

<div id="app">
    <component :is="currentView"></component>
</div> 
var Home = { 
    template: '<p>Welcome home!</p>' 
};

var app = new Vue({ 
    el: '#app',
    data: { 
        currentView: Home
    }
}) 

异步组件

<div id="app">
    <child-component></child-component> 
</div> 
Vue.component('child-component', function (resolve, reject) {
    window.setTimeout(function () {
        resolve({
            template:'<div>我是异步渲染的</div>'
        }); 
    },2000); 
});

var app = new Vue({ 
    el: '#app' 
}) 

工厂函数接收一个 resolve 回调,在收到从服务器下载的组件定义时调用。也可以调用 reject( reason)指示加载失败。这里 setTimeout 只是为了演示异步,具体的下载逻辑可以自己决定, 比如把组件配置写成一个对象配置,通过 Ajax 来请求,然后调用 resolve 传入配置选项。

$nextTick

异步更新队列: Vue 在观察到数据变化时并不是直接更新 DOM,而是开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和 DOM 操作。然后, 在下一个事件循环 tick 中, Vue 刷新队列井执行实际(己去重的)工作。

如果你用一个 for 循环来动态改变数据 100 次,其实它只会应用最后一次改变,如果没有这种机制, DOM 就要重绘 100 次,这固然是一个很大的开销。

<div id="app">
    <div id="div" v-if="showDiv">这是一段文本</div>
    <button @click="getText">获取 div 内容</button>
</div>
var app = new Vue({ 
    el: '#app',
    data: { 
        showDiv: false
    },
    methods: {
        getText: function () {
            this.showDiv = true;
            // 没有使用$nextTick去获取text就会报错
            this.$nextTick (function () {
                var text = document.getElementByid ('div').innerHTML;
                console.log(text);
            });
        }
    }
});

理论上,我们应该不用去主动操作 DOM,因为 Vue 的核心思想就是数据驱动 DOM,但在很 多业务里,我们避免不了会使用一些第三方库,比如 popper.js、 swiper 等,这些基于原生 JavaScript 的库都有创建和更新及销毁的完整生命周期,与 Vue 配合使用时,就要利用好$nextTick。

X-Templates

Vue 提供了另一种定义模板的方式,在

如果没有使用 webpack、 gulp 等工具,组件 template 的内容会很冗长、复杂,故这里可以使用 X-Templates。

<div id="app">
    <my-component></my-component>
    <script type="text/x-template" id="my-component">
        <div>这是组件的内容</div>
    </script> 
</div> 
Vue.component ('my-component',{
    template: '#my-component'
});

var app =new Vue({ 
    el: '#app' 
}); 

手动挂载实例

在一些非常特殊的情况下,我 们需要动态地去创建 Vue 实例, Vue 提供了 Vue.extend 和$mount 两个方法来手动挂载一个实例。

如果 Vue 实例在实例化时没有收到 el 选项,它就处于“未挂载”状态,没有关联的 DOM 元 素。可以使用$mount()手动地挂载一个未挂载的实例。

<div id="mount-div">
</div> 
var MyComponent = Vue.extend ({
     template: `<div>Hello: {
   
   { name } }</div>`,
     data: function () { 
        return {
            name: 'Aresn'
        }
    }
});

new MyComponent().$mount('#mount-div'); 

如果$mount没有提供参数,模板将被渲染为文档之外的的元素,并且你必须使用原生DOM API把它插入文档中

自定义指令

基本用法

自定义指令的注册方法和组件很像,也分全局注册和局部注册,比如注册一个 v-focus 的指令, 用于在<input>、<textarea>元素初始化时自动获得焦点,两种写法分别是:

// 全局注册 
Vue.directive('focus', {
    // 指令选项
});
// 局部注册
var app =new Vue({ 
    el :'#app',
    directives: { 
        focus: { 
            // 指令选项
        }
    }
});

自定义指令的钩子函数

自定义指令的选项是由几个钩子函数组成的,每个都是可选的。

  • bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定 时执行一次的初始化动作。
  • inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
  • update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后 的绑定值,可以忽略不必要的模板更新。
  • componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
  • unbind: 只调用一次,指令与元素解绑时调用。

可以根据需求在不同的钩子函数内完成逻辑代码,例如上面的 v-focus,我们希望在元素插入 父节点时就调用,那用到的最好是 inserted。示例代码如下:

<div id='app'>
    <input type='text' v-focus>
</div> 
Vue.directive('focus',{
    inserted: function (el) {
        // 聚焦元素 
        el.focus();
    }
});

var app =new Vue({ 
    el: '#app' 
}); 

每个钩子函数都有几个参数可用,比如上面我们用到了 el。它们的含义如下:

  • el 指令所绑定的元素,可以用来直接操作 DOM。
  • binding 一个对象,包含以下属性:
    • name 指令名,不包括 v-前缀。
    • value 指令的绑定值,例如 v-my-directive=’1 + 1’, value 的值是2。
    • oldValue 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用.无论值是否改变都可用。
    • expression 绑定值的字符串形式。 例如 v-my-directive=‘1 + 1’, expression 的值是’1 + 1’。
    • arg 传给指令的参数。例如 v-my-directive:foo, arg 的值是 foo。
    • modifiers 一个包含修饰符的对象。 例如 v-my-directive.foo.bar,修饰符对象 modifiers 的值是{ foo: true, bar: true }。
  • vnode Vue 编译生成的虚拟节点,在进阶篇中介绍。
  • oldVnode 上一个虚拟节点仅在 update 和 componentUpdated 钩子中可用。
<div id='app'> 
    <div v-test :msg.a.b='message'></div> 
</div> 
Vue.directive('test',{
    bind: function(el, binding, vnode) {
        var keys= [];
        for (var i in vnode) { 
            keys.push(i);
        }
        el.innerHTML = 
            'name:'+ binding.name +'<br>'+ 
            'value:'+ binding.value +'<br>'' +
            'expression'+ binding.expression +'<br>'+
            'argument:'+ binding. arg +'<br>'+ 
            'modifiers:'' + JSON.stringify(binding.modifiers) +'<br>'+
            'vnode keys:' + keys.join (',');
    }
});

执行后,<div>的内容会使用 innerHTML 重置

name: test 
value: some text 
expression: message 
argument: msg 
modifiers: {"a":true ,"b": true} 
vnode keys: tag , data , children,text,elm, ns , context , funct工onalContext , key , componentOpti ons ,componentinstance, parent, raw, isStatic, isRootinsert, isComment, isCloned, isOnce

注:非原创,忘了从哪个技术群借的笔记

猜你喜欢

转载自blog.csdn.net/weixin_44158539/article/details/118658100