初识Vue(上)

88 阅读10分钟

初识Vue

vue是什么?

image-20230820110850516.png

在vue官网的简介是:用于 构建用户界面1 的 渐进式2 框架3

image-20230820111223712.png

构建用户界面:基于数据动态渲染出用户看到的页面

渐进式:循序渐进逐步学习,使用

框架:一套完整的项目解决方案,可以极大地提高开发的效率

既然那么好用,让我们来盘一盘这个vue

vue中的MVVM

image-20230826201735352.png

  • M指的是model(模型),对应data中的数据。
  • V指的是view(视图),一个展示用户界面的模板,可以简单的理解为HTML标签页面。
  • MV指的是ViewModel(视图模层),它是Vue的实例对象,一个连接view和model的桥梁,负责把model对象封装成可以显示和接受输入的界面对象。

vue的基本使用

核心步骤(4步):

  1. 准备容器

  2. 引包(官网) — 开发版本/生产版本

  3. 创建Vue实例 new Vue()

  4. 指定配置项,渲染数据

    1. el:指定挂载点
    2. data提供数据

创建vue实例,初始化渲染

image-20230820115249589.png

来到vue2的官网看看该如何使用

vue2

依照上面的顺序

 //准备容器 (Vue所管理的范围)
        <div id="app">{{ message }}</div>
​
        //引包 (开发版本包 / 生产版本包) 官网
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
        <script>
            //创建实例
            const box = new Vue({
              // 制定 vue 托管的区域
                el: '#app',
                // 渲染的数据
                data: {
                    message: 'Hello Vue!'
                }
            })

这样的话data里面的数据就被渲染到页面上了

只能渲染由vue托管的区域,没有托管的区域不会动态渲染

插值表达式{{ }}

数据绑定最常见的形式就是使用“Mustache”语法 (小胡子语法) 的文本插值

作用:利用表达式进行插值,渲染到页面上

语法:{{ 表达式}}

<span>Message: {{ msg }}</span>

所谓的表达式,就是一段可以被求值的代码,js引擎会将其计算并最终得出一个结果

money + 100
money - 100
money * 10
money / 10 
price >= 100 ? '真贵':'还行'
obj.name
arr[0]
fn()
obj.fn()

以上这些都是表达式

可以简单的直接渲染数据,既然支持表达式那么也可以往里面写一些复杂的计算表达式,就像这样

<h3>{{title}}<h3>
​
<p>{{nickName.toUpperCase()}}</p>
​
<p>{{age >= 18 ? '成年':'未成年'}}</p>
​
<p>{{obj.name}}</p>
​
<p>{{fn()}}</p>

当msg里面的数据发生变化的时候,对应页上的信息也会进行动态的渲染和更新

通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定:

<span v-once>这个将不会改变: {{ msg }}</span>

注意:

数据必须存在

插值表达式,只能支持表达式,而非语句: if ,for...

不能够在标签中使用

响应式特性

当data里面的数据发生变化的时候,对应页上的信息也会进行动态的渲染和更新

image-20230820124523229.png

data中的数据, 最终会被添加到实例上

① 访问数据: "实例.属性名"

② 修改数据: "实例.属性名"= "值"

vue指令

v-html

作用:设置元素的innerHTML

语法: v-html = 表达式

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令

 <div id="app">
    <div v-html="msg"></div>
      </div>
       <script> 
           const app = new Vue({
         el: '#app',
          data: {
                msg: '<h1>燕子,你别走!!!没了你我可怎么活啊!</h1>'
               }
           })
       </script>

v-if

image-20230820130841220.png

v-if 底层原理:通过创建 / 删除 dom 元素来实现盒子的显示隐藏,当表达式的值为 true 时就显示,为 false 时就隐藏

适用于初始状态就决定了显示隐藏的场景

v-show

v-show 底层原理: 通过设置 display:none,来改变盒子的显示隐藏

当表达式的值为 true 时就显示,为 false 时就隐藏

适用于频繁切换显示隐藏的场景

v-else ,v-else-if

  1. 作用:辅助v-if进行判断渲染
  2. 语法:v-else v-else-if="表达式"
  3. 需要紧接着v-if使用
  <div id="app">
    <p v-if="gender===0">性别:♂ 男</p>
    <p v-else>性别:♀ 女</p>
    <hr>
    <p v-if="score>=90">成绩评定A:奖励电脑一台</p>
    <p v-else-if="score>=70">成绩评定B:奖励周末郊游</p>
    <p v-else-if="score>=60">成绩评定C:奖励零食礼包</p>
    <p v-else>成绩评定D:惩罚一周不能玩手机</p>
  </div>
​
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    // 目标:
    // 1. 根据条件渲染姓名
    // 2. 根据成绩来渲染奖励
    const app = new Vue({
      el: '#app',
      data: {
        gender: 0,
        score: 95
      }
    })
  </script>

image-20230820134529444.png

v-on

作用: 注册事件 = 添加监听 + 处理逻辑

语法:

  1. v-on :事件名 = "内联语句"
  2. v-on: 事件名 = "methods中的函数名"

简写形式

@事件名

        <div id="app">
            <button @click={{count--}}>-</button>
            <span>{{ count }}</span>
            <button @click={{count++}}>+</button>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
        <script>
            // 目标: 点击 - 让数字减一, 点击 + 让数字加一
            const app = new Vue({
                el: '#app',
                data: {
                    count: 100
                }
            })
        </script>

methods 中存放函数

只要是定义在 methods 中的函数,最终都会放到实例对象上,所以内部的 this 指向实例对象

  <div id="app">
    <button @click="isShow = !isShow">切换显示隐藏</button>
    <button @click="change">切换显示隐藏</button>
    <h1 v-show="isShow">我又出来了</h1>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标:
     *    点击切换 h1 标签显示隐藏
     */
    const app = new Vue({
      el: '#app',
      data: {
        isShow: true
      },
      methods: {
        change() {
          this.isShow = !this.isShow
        }
      }
    })

v-on调用传参

  <div id="app">
            <div class="box">
                <h3>小黑自动售货机</h3>
                <button @click="buy(5)">可乐5元</button>
                <button @click="buy(10)">咖啡10元</button>
            </div>
            <p>银行卡余额:{{ money }}元</p>
        </div>
​
        <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
        <script>
            /**
             * 目标:
             *  点击不同按钮, 银行卡余额减少对应的金额
             */
            const app = new Vue({
                el: '#app',
                data: {
                    money: 100
                },
                methods: {
                    buy(price) {
                        this.money -= price
                    }
                }
            })

v-bind

作用:动态设置标签的属性值

语法: v-bind:属性名="表达式"

简写:

:属性名 = "表达式"

以下是一些常见的HTML标签属性

1.src 属性(用于图像、音频、视频等):

<img :src="imageSource">
<audio :src="audioSource"></audio>
<video :src="videoSource"></video>

2.href 属性(用于链接):

<a :href="externalLink">Visit Website</a>

3.title 和 alt 属性(用于提示信息):

<img :title="imageTitle" :alt="imageAlt" src="imageSource">

4.disabled 属性(用于禁用表单元素):

<button :disabled="isDisabled">Submit</button>

5.placeholder 属性(用于表单元素的占位符文本):

<input :placeholder="inputPlaceholder">

6.value 属性(用于表单元素的值):

<input :value="inputValue">

7.readonly 属性(用于设置表单元素为只读):

<input :readonly="isReadOnly">

8.checked 属性(用于复选框和单选按钮):

<input type="checkbox" :checked="isChecked">
<input type="radio" :checked="isSelected">

9.data-属性(用于存储自定义数据):

<div :data-custom-value="customData"></div>
 <div id="app">
    <img :src="imgUrl" :title="msg" alt="">
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <script>
    /**
     * 目标:
     *  使用 v-bind 指令动态绑定标签属性
     */
    const app = new Vue({
      el: '#app',
      data: {
        imgUrl: './imgs/10-02.png',
        msg: 'hello'
      }
    })
​

v-bind 操作 class 类名

语法 :class ="{对象}"

设置对象使用布尔值控制是否使用这个类名,比较常用动态设置类名

 <div id="app">
    <div class="box" :class="{pink:flag}">键盘敲烂,月薪过万</div>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    flag: true
                }
            })
        </script>

语法 :class="[数组]"

使用数组一次性设置多个类名,或删除多个类名

 <div id="app">
            <div class="box" :class="['pink','big']">今天天气真不挫!</div>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
        <script>
            const app = new Vue({
                el: '#app',
                data: {
                    flag: true
                }
            })
        </script>

v-bind 操作 style 类名

语法 :style = "{ 样式属性 }"

  <div id="app">
    <div class="box" :style="{width: '50rem',height: '18.75rem'}"></div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
​
      }
    })
  </script>

v-for

作用:基于数组循环,多次整个渲染整个元素

语法: v-for ="(item,index) in list"

  • item 是数组中的每一项
  • index 是每一项对应的索引,不需要可以省略
  • list是被遍历的数组
    const app = new Vue({
        el: '#app',
        data: {
           booksList: [
           { id: 1, name: '《红楼梦》', author: '曹雪芹' },
           { id: 2, name: '《西游记》', author: '吴承恩' },
           { id: 3, name: '《水浒传》', author: '施耐庵' },
           { id: 4, name: '《三国演义》', author: '罗贯中' }
            ]
             },
            methods: {
            del(id) {
            this.booksList =this.booksList.filter(item=> {
                          this.booksList = item.id !== id
                        })
                    }
                }
            })

key属性

当使用 v-for 来渲染一个列表时,Vue 需要一个唯一的 key 值来追踪每个循环项。这有助于 Vue 在更新列表时识别出哪些项被添加、删除或移动了,从而提供更快速的 DOM 更新以及更精准的变化追踪。

<template>
  <ul>
    <li v-for="(item, index) in items" :key="item.id">
      {{ item.name }}
    </li>
  </ul>
</template>

v-modal

作用:双向数据绑定,快速获取或设置表单元素内容

什么是双向数据绑定?

Vue是一个MV VM框架, 即数据双向绑定, 即当数据发生变化的时候, 视图也就发生变化, 当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue的精髓之处了。

v-model 会根据控件类型自动选取正确的方法来更新元素。

<div id="app">
    账户:<input type="text"> <br><br>
    密码:<input type="password"> <br><br>
    <button>登录</button>
    <button>重置</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: '',
        password: ''
      },
    })
  </script>

1681913125738.png

复选框的数据绑定

复选框如果是一个为逻辑值

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
  <p>单个复选框:</p>
  <input type="checkbox" id="checkbox" v-model="checked">
  <label for="checkbox">{{ checked }}</label>
</div><script>
new Vue({
  el: '#app',
  data: {
    checked : false,
  }
})
</script>
</body>
</html>

如果是多个则绑定到同一个数组,会把选中的选项里面的 value 值,添加到数组中

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
  <p>多个复选框:</p>
  <input type="checkbox" id="runoob" value="苹果" v-model="checkedNames">
  <label for="runoob">苹果</label>
  <input type="checkbox" id="google" value="香蕉" v-model="checkedNames">
  <label for="google">香蕉</label>
  <input type="checkbox" id="taobao" value="荔枝" v-model="checkedNames">
  <label for="taobao">荔枝</label>
  <br>
  <span>选择的值为: {{ checkedNames }}</span>
</div><script>
new Vue({
  el: '#app',
  data: {
    checkedNames: []
  }
})
</script>
</body>
</html>

单选框的数据绑定

<div id="app">
  <!-- 1.name:  给单选框加上 name 属性可以分组,同一组互相会互斥 -->
  <!-- 2.value: 给单选框加上 value 属性,用于提交给后台的数据 -->
  性别: 
    <input v-model="gender" name="gender" value="male" type="radio">男
    <input v-model="gender" name="gender" value="female" type="radio">女
    <br><br>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.14/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      gender: 'female',
    }
  })
</script>

下拉菜单的数据绑定

<div id="app">
  <!-- 1. option 需要设置 value 值,提交给后台 -->
  <!-- 2. select 的 value 值,关联了选中的 option 的 value 值 -->
  <!-- 注意: 下拉选择框使用 v-model 要绑定在 select 上 -->
  所在城市:
  <select v-model="city">
    <option value="beijing">北京</option>
    <option value="shanghai">上海</option>
  </select>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.14/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      city: 'beijing',
    }
  })
</script>

指令修饰符

1.v-model修饰符

.lazy

在默认情况下, v-model 在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:

<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >

.number

如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:

<input v-model.number="age" type="number">

.trim

如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:

<input v-model.trim="msg">

2.按键修饰符

Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">

记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:

<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">

全部的按键别名:

  • .enter
  • .tab
  • .delete (捕获 "删除" 和 "退格" 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

系统修饰键:

  • .ctrl
  • .alt
  • .shift
  • .meta

鼠标按钮修饰符:

  • .left
  • .right
  • .middle

3.事件修饰符

Vue 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。

Vue 通过由点 . 表示的指令后缀来调用修饰符。

  • .stop - 阻止冒泡
  • .prevent - 阻止默认事件
  • .capture - 阻止捕获
  • .self - 只监听触发该元素的事件
  • .once - 只触发一次
  • .left - 左键事件
  • .right - 右键事件
  • .middle - 中间滚轮事件
<!-- 阻止单击事件冒泡 -->
<a @click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联  -->
<a @click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form @submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div @click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div @click.self="doThat">...</div><!-- click 事件只能点击一次,2.1.4版本新增 -->
<a @click.once="doThis"></a>

计算属性 computed

计算属性,字如其名,首先它是属性,其次有计算的“功能”

说的官方一点:计算属性就是当其依赖属性的值发生变化时,这个属性的值会自动变化,与之相关的DOM部分也会同步自动更新。

在computed配置项中添加我们的计算属性,在属性里面写我们的逻辑代码

注意:计算属性其实是属性,在页面上使用只需要用属性值,不要带(),不然就变成方法了

<div id="app">
    <h3>小黑的礼物清单</h3>
    <table>
      <tr>
        <th>名字</th>
        <th>数量</th>
      </tr>
      <tr v-for="(item, index) in list" :key="item.id">
        <td>{{ item.name }}</td>
        <td>{{ item.num }}个</td>
      </tr>
    </table>
​
    <!-- 目标:统计求和,求得礼物总数 -->
    <p>礼物总数:{{totalCount}} 个</p>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 现有的数据
        list: [
          { id: 1, name: '篮球', num: 1 },
          { id: 2, name: '玩具', num: 2 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      computed: {
        totalCount() {
          return this.list.reduce((sum,item)=>sum+item.num,0)
        }
      }
    })
计算属性computedmethods的区别

computed是一个方法,而methods里面也是一个方法,那么他们之间的区别是什么呢?

我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

我们可以通过多次调用,打印出来看看结果有什么不一样

 <div id="app">
    <h3>小黑的礼物清单🛒<span>?</span></h3>
    <table>
      <tr>
        <th>名字</th>
        <th>数量</th>
      </tr>
      <tr v-for="(item, index) in list" :key="item.id">
        <td>{{ item.name }}</td>
        <td>{{ item.num }}个</td>
      </tr>
    </table>
​
    <p>礼物总数:{{ getNum() }} 个</p>
    <p>礼物总数:{{ getNum() }} 个</p>
    <p>礼物总数:{{ getNum() }} 个</p>
    <p>礼物总数:{{ getNum() }} 个</p>
    <p>礼物总数:{{ getNum() }} 个</p>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 现有的数据
        list: [
          { id: 1, name: '篮球', num: 3 },
          { id: 2, name: '玩具', num: 2 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      computed: {
        totalCount () {
          console.log('我是 computed 里的求和属性');
          let total = this.list.reduce((sum, item) => sum + item.num, 0)
          return total
        }
      },
      methods: {
        getNum() {
          console.log('我是 methods 里的求和属性');
          return this.list.reduce((sum, item) => sum + item.num, 0)
        }
      }
    })

image-20230823114418161.png

可以清晰地看到,用methods方法数据每更新一次就会被调用一次,而computed方法只被调用了一次

优点:计算属性最重要的特性: 带缓存

在第一次使用了该属性时进行计算,计算完了后他就会把结果存起来,后面有用到会直接在缓存里面把结果取出来

只在相关响应式依赖发生改变(相关的属性变化)时它们才会重新求值

这样做的主要目的也是为了提高性能

计算属性的完整写法

计算属性都包含有一个get和一个set,计算属性会默认使用 get函数,如果你要使用 set函数,那么你必须要手动写出 set 函数

    const app = new Vue({
      el: '#app',
      data: {
        firstName: '李',
        lastName: '雷',
      },
      methods: {
        change() {
          this.fullName = '韩梅梅'
        }
      },
      computed: {
        fullName: {
          // 当访问这个计算属性时, get 函数会自动执行,并将返回值作为计算属性的值
         get() {
          return this.firstName + this.lastName
         },
        //  当修改这个计算属性时, set 函数会自动执行, 并将修改的新值作为参数传递过来
         set(val) {
          this.firstName = val.substring(0,1)
          this.lastName = val.substring(1)
         }
        }
      }
    })

watch侦听器

作用:监视数据变化,执行业务逻辑或是异步操作

            const app = new Vue({
                el: '#app',
                data: {
                    words: ''
                },
                watch: {
                    //要监听什么数据,就以什么数据命名,定义函数
                    // 该函数会在数据变化时自动执行,并携带两个参数
                    // 参数一:新值
                    // 参数二:旧值 ,不常用
                    words(newValue,oldValue) {
                        console.log(value)
                    }
                }
              
            })

完整写法:

  • deep: true 对复杂类型深度监视
  • immediate: true 初始化立刻执行一次handler方法
watch: {// watch 完整写法
    数据属性名: {
      deep: true, // 深度监视(针对复杂类型)
      immediate: true, // 是否立刻执行一次handler
      handler (newValue) {
        console.log(newValue)
      }
   }
}

生命周期

一个Vue实例从 创建销毁 的整个过程

vue的生命周期分为四个阶段:

①创建 ②挂载 ③更新 ④销毁

image-20230826115137667.png

Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】

这个时候我们就可以在【特定阶段】运行自己的代码

  1. 实例、组件通过new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载,只是一个空壳,无法访问到数据和真实的dom,一般不做操作
  2. 挂载数据,绑定事件等等,然后执行created函数,这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数,在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取
  3. 接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取
  4. 接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom等事情...
  5. 当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染,一般不做什么事儿
  6. 当更新完成后,执行updated,数据已经更改完成,dom也重新render完成,可以操作更新后的虚拟dom
  7. 当经过某种途径调用$destroy方法后,立即执行beforeDestroy,一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等
  8. 组件的数据绑定、监听...去掉后只剩下dom空壳,这个时候,执行destroyed,在这里做善后工作也可以

image-20230826115225732.png

生命周期图示

20190725165224557.png

生命周期钩子实例阶段说明能否获取到data能否获取到 methods
beforeCreate创建前实例已初始化,但数据观测,watch/event 事件回调还未配置NONO
created创建后已完成如下配置,数据观测 (data observer),property 和方法的运算,watch/event 事件回调NOOK
beforeMount挂载前dom已初始化,但并未挂载和渲染OKOK
mounted挂载后dom已完成挂载和渲染OKOK
beforeUpdate更新前数据已改变,但dom为更新OKOK
updated更新后dom已更新OKOK
beforeDestroy销毁前实例销毁前,实例仍然可用OKOK
destroyed销毁后实例已销毁,所有指令被解绑,事件监听器被移除,子实例都被销毁OKOK