Vue 学习笔记 -- 1 Vue 核心

Vue 学习笔记 – 1 Vue 核心

1. Vue 核心

1.1 Vue 简介
  • 动态构建用户界面的渐进式 JavaScript 框架。

  • 借鉴 Angular 的模板和数据绑定技术。

  • 借鉴 React 的组件化和 虚拟DOM 技术。

  • 编码简洁, 体积小, 运行效率高, 适合移动/PC 端开发。

  • 中文官网

1.2 初识 Vue
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>初识 Vue </title>
    <!-- 引入 Vue -->
    <script type="text/javascript" src="../js/vue.js"></script> <!-- 之后的代码笔记中将省略头部非重要信息 -->
</head>
<body>
    <!--
        初识 Vue:
            1. 想让 Vue 工作,就必须创建一个 Vue 实例,且要传入一个配置对象;
            2. root 容器里的代码依然符合 html 规范,只不过是混入了一些特殊的 Vue 语法;
            3. root 容器里的代码被称为 Vue 模板;
            4. Vue 实例和容器是一一对应的;
            5. 真实开发中只有一个 Vue 实例,并且会配合组件一起使用;
            6. {{xxx}} 中的 xxx 要写 js 表达式,且 xxx 可以自动读取到 data 中的所有属性;
            7. 一旦 data 中的数据发生改变,那么页面中用到该数据的地方也会自动更新;

            注意区分:js 表达式 和 js 代码(语句)
                js 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:
                    例如: a, a + b, demo(1), x === y ? 'a' : 'b' 等等
                    
                js 代码(语句)
                    例如:if(){} , for(){} 等等
    -->
    

    <!-- 准备一个容器 -->
    <div id="root">
        <h1>Hello {{name}}!</h1>
    </div>

    <script type="text/javascript" >
        Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
        // 创建 Vue 示例
        new Vue({
            el: '#root',//el 用于指定当前Vue实例为哪个容器提供服务,值通常为 css 选择器字符串;
            data: { //  data 中用于存储数据,数据供 el 所指定的容器使用,值暂时先写成一个对象。
                name: '凌宸1642'
            }
        })
    </script>
</body>
1.3 Vue 模板语法
<body>
    <!--
      Vue 模板语法有 2 大类:
        1. 插值语法:
          功能:用于解析 标签体 内容。
          写法:{{xxx}}, xxx 是 js 表达式,且可以直接读取到 data 中的所有属性。
        2. 指令语法:
          功能:用于解析标签(包括,标签属性,标签体内容,绑定事件.....)。
          举例:v-bind:href="xxx" 或简写为 :href="xxx",xxx 同样要写 js 表达式
                且可以直接读取到 data 中的所有属性。
          备注:Vue 中有很多的指令,且形式都是:v-???, 此处只是拿 v-bind 举例。
    -->
    <!-- 准备一个容器 -->
    <div id="root">
        <h1>插值语法</h1>
        <h3>Hello {{name}}!</h1>
        <br />
        <h1>指令语法</h1>
        <!-- <a v-bind:href="url" >点我去学习1</a> -->
        <!-- <a :href="url" >点我去学习2</a> -->
        <a :href="school.url" >点我去{{school.name}}学习</a>
    </div>

    <script type="text/javascript" >
      Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示

      new Vue({
        el: '#root',
        data: {
          name: 'lingchen',
          // url: 'https:www.lingchen1642.top'
          school: {
            name: '尚硅谷',
            url: 'https://www.atguigu.com'
          }
        }
      })
    </script>
</body> 
1.4 数据绑定
<body>
    <!-- 
      Vue 中有两种数据绑定的方式:
        1. 单向绑定(v-bind):数据只能从 data 流向页面。
        2. 双向绑定(v-model): 数据不仅能从 data 流向页面,还可以从页面流向 data。
        备注:
          1. 双向绑定一般都应用在表单类元素上(如:imput,select 等)。
          2. v-model:value 可以简写为 v-model,因为 v-model 默认收集的就是 value 值。
    -->

    <!-- 准备一个容器 -->
    <div id="root">
      <!-- 普通写法 -->
      <!-- 单向数据绑定:<input type="text" v-bind:value="name"> <br/>
      双向数据绑定:<input type="text" v-model:value="name">  -->
      <!-- 简写 -->
      单向数据绑定:<input type="text" :value="name"> <br/>
      双向数据绑定:<input type="text" v-model="name"> 
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示

    new Vue({
      el: '#root',
      data: {
        name:'凌宸'
      }
    })
</script> 
1.5 el与data的两种写法
<body>
    <!-- 
      data 与 el 的两种写法:
        1. el 有两种写法
          - new Vue 时候配置 el 属性。
          - 先创建 Vue 实例 app,随后再通过 app.$mount('#root') 指定 el 的值。
        2. data 有两种写法
          - 对象式
          - 函数式
          - 如何选择:目前都可以,学习到组件后,data 必须使用函数式。
        3. 一个重要的原则
          由 Vue 管理的函数,一定不能写箭头函数,一旦写了箭头函数,this 就不再是 Vue 实例了。
    -->
    <!-- 准备一个容器 -->
    <div id="root">
        <h1>你好啊! {{name}}</h1>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    // el 的两种写法
    /* const app = new Vue({
        // el: '#root',  // 第一种写法
        data: {
            name: '凌宸'
        }
    })
    app.$mount('#root') // 第二种写法 */

    // data 的两种写法
    const app = new Vue({
        el: '#root',  
        // data: {  // 第一种写法,对象式
        //     name: '凌宸'
        // }
        data:function(){ // 第二种写法,函数式
            return {
                name: '凌宸'
            }
        }
    })
</script> 
1.6 Vue中的MVVM
<body>
    <!-- 
      MVVM 模型
          M:模型(Model): data 中的数据
          V:视图(View): 模板代码
          VM:视图模型(ViewModel): Vue 实例
      观察发现:
          data中的所有属性,最后都出现在了 vm 身上。
          vm 身上的所有的属性及 Vue 原型上所有属性,在 Vue 模板中都可以直接时候用。
    -->
    <!-- 准备一个容器 -->
    <div id="root">
      <h1>学校名称:{{name}}</h1>
      <h1>学校地址:{{address}}</h1> 
      <h1>测试一下:{{$options}}</h1>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示

    const vm = new Vue({
      el: '#root',
      data: {
        name: '尚硅谷',
        address: '江西南昌'
      }
    })
    console.log(vm)
</script> 
1.7 数据代理
1.7.1 回顾Obejct.defineProperty方法
<body>
    <div id="root"></div> <!-- 准备一个容器 -->
</body>
<script type="text/javascript" >
    let number = 18;
    let person = {
        name: '张三',
        sex: '男',
        // age: 18
    }
    Object.defineProperty(person, 'age', {
        // value: 20,
        // enumerable: true,   // 控制属性是否可以被枚举,默认值是 false
        // writable: true,     // 控制属性是否可以被修改,默认值是 false
        // configurable: true  // 控制属性是否可以被删除,默认值是 false
        
        // 当有人读取 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)
    console.log(Object.keys(person))
</script> 
1.7.2 Vue中的数据代理
 <body>
    <!--
        Vue 中的数据代理:通过 vm 对象来代理 data 对象中属性的操作 (读/写)
        Vue 中数据代理的好处:更加方便的操作 data 中的数据
        基本原理:
            通过 Object.defineProperty() 把 data 对象中所有属性添加到 vm 上;
            为每一个添加到 vm 上的属性,都指定一个 getter/setter;
            在 getter/setter 内部去操作(读/写) data 中对应的属性。
    -->
    <!-- 准备一个容器 -->
    <div id="root">
        <h1>学校名称:{{name}}</h1>
        <h1>学校地址:{{address}}</h1>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示

    const vm = new Vue({
        el: '#root',
        data:{
            name: '南昌大学',
            address: '江西南昌'
        }
    })
</script> 
1.7.3 数据代理图示

在这里插入图片描述

1.8 事件处理
1.8.1 事件的基本使用
<body>
    <!--
        事件的基本使用
            1.使用 v-on:xxx 或 @xxx 绑定事件,其中 xxx 是事件名;
            2.事件的回调需要配置在 methods 对象中,最终会在 vm 上;
            3.methods 中配置的函数,不要用箭头函数!否则 this 就不是 vm 了;
            4.methods 中配置的函数,都是被 Vue 所管理的函数,this 的指向是 vm 或 组件实例对象;
            5.@click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参。
    -->
    <!-- 准备一个容器 -->
    <div id="root">
      <h1>欢迎来到{{name}}学习</h1>
      <button v-on:click="showInfo1">点我提示信息1(不传参)</button>
      <button @click="showInfo2($event,666)">点我提示信息2(传参)</button>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示

    const vm = new Vue({
      el: '#root',
      data: {
        name: '尚硅谷',
      },
      methods: {
        showInfo1(event){
          // console.log(event) // PointerEvent{...} 点击事件
          // console.log(event.target.innerText)
          // console.log(this) // 此处的 this 是 vm  
          alert('同学你好!')
        },
        showInfo2(event, number){
          // console.log(event) 
          // console.log(this) // 此处的 this 是 vm  
          alert('同学你好!!'+ number)
        }
      }
    })
</script> 
1.8.2 事件修饰符
<style>
     *{ margin-top: 20px; }
     .demo1{ height: 50px; background-color: skyblue; }
     .box1{ padding: 5px; background-color: skyblue; }
     .box2{ padding: 5px; background-color: pink; }
     .list{ width: 200px; height: 200px; background-color: peru; overflow: auto;}
     li{ height: 100px;}
</style> 
<body>
    <!--
        Vue 中的事件修饰符
            1.prevent:阻止默认事件(常用)
            2.stop:阻止事件冒泡(常用)
            3.once:事件只触发一次(常用)
            4.capture:使用事件的捕获模式
            5.self:只有 event.target是当前操作的元素时才触发事件
            6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕
    -->
    <!-- 准备一个容器 -->
    <div id="root">
        <h1>欢迎来到{{name}}学习</h1>
        <!-- prevent:阻止默认事件(常用) --> 
        <a href="http://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>
        <!-- stop:阻止事件冒泡(常用) -->
        <div class="demo1"  @click="showInfo">
          <button @click.stop="showInfo">点我提示信息</button>
          <!-- 修饰符可以连着写 -->
          <a href="http://www.baidu.com" @click.prevent.stop="showInfo">点我提示信息</a>
        </div>
        <!-- once:事件只触发一次(常用) -->
        <button @click.once="showInfo">点我提示信息</button>
        <!-- capture:使用事件的捕获模式 -->
        <div class="box1" @click.capture="showMsg(1)">
          div1
          <div class="box2" @click="showMsg(2)">
            div2
          </div>
        </div>
        <!-- self:只有 event.target是当前操作的元素时才触发事件 -->
        <div class="demo1" @click.self="showInfo">
          <button @click.once="showInfo">点我提示信息</button>
        </div>
        <!-- passive:事件的默认行为立即执行,无需等待事件回调执行完毕 -->
        <ul @wheel.passive="demo"  class="list">
          <li>1</li>
          <li>2</li> 
        </ul>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示

    const vm = new Vue({
        el: '#root',
        data: {
            name: '尚硅谷',
        },
        methods:{
            showInfo(){
                alert('同学你好')
            },
            showMsg(number){
              console.log(number)
            },
            demo(){
              for(let i = 0; i < 100000; i ++){
                console.log('#')
              }
              console.log('累坏了')
            }
        }
    })
</script> 
1.8.3 键盘事件
<body>
    <!--
        Vue 中常用的按键别名
            回车 ==> enter
            删除 ==> delete (捕获"删除"和"退格"键)
            退出 ==> esc
            空格 ==> space
            换行 ==> tab (特殊,需要配合 keydown 一起使用)
            上 ==> up
            下 ==> down
            左 ==> left
            右 ==> right

        Vue 未提供别名的按键,可以使用按键原始的 key值去绑定,但注意要转为 kebab-case(短横线命名法)

        系统修饰符(用法特殊):ctrl, alt, shift, meta
            配合 keyup 使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
            配合 keydown 使用:正常触发事件
        
        也可以使用 keyCode 去指定具体的按键(不推荐)

        Vue.config.keyCodes.自定义别名 = 键码; 可以是自定义按键别名(不推荐)
    -->
    <!-- 准备一个容器 -->
    <div id="root">
        <h1>欢迎来到{{name}}学习</h1>
        <input type="text" placeholder="按下回车键提示输入" @keyup.huiche="showInfo">
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    Vue.config.keyCodes.huiche = 13;
    const vm = new Vue({
        el:'#root',
        data: {
            name: '尚硅谷'
        },
        methods:{
            showInfo(e){
                console.log(e.target.value)
            }
        }
    })
</script> 
1.9 计算属性
1.9.1 姓名案例-插值语法实现
<body>
    <!-- 准备一个容器 -->
    <div id="root">
        姓:<input type="text" v-model="firstNmae"><br/>
        名:<input type="text" v-model="lastNmae"><br/>
        全名:<span>{{firstNmae.slice(0,3)}}-{{lastNmae}}</span>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
        el: '#root',
        data: {
            firstNmae: '张',
            lastNmae: '三'
        }
    })
</script> 
1.9.2 姓名案例-methods实现
<body>
    <!-- 准备一个容器 -->
    <div id="root">
        姓:<input type="text" v-model="firstNmae"><br/>
        名:<input type="text" v-model="lastNmae"><br/>
        全名:<span>{{fullName()}}</span>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
        el: '#root',
        data: {
            firstNmae: '张',
            lastNmae: '三'
        },
        methods: {
            fullName(){
                return this.firstNmae + '-' + this.lastNmae;
            }
        }
    })
</script> 
1.9.3 姓名案例-计算属性实现
<body>
		<!--
			计算属性:
					定义:要用的属性不存在,要通过已有的属性计算得来
					原理:底层借助了 Object.defineProperty 方法提供的 getter 和 setter
					get 函数的执行时机:
							初次读取时会执行一次;当所依赖的数据发生改变时会再次调用
					优势:与 methods 实现相比,内部有缓存机制(复用),效率更高,调试方便
					备注:计算属性最终胡出现在 vm 上,直接读取使用即可;
								如果计算属性要被修改,则必须写 set 函数去响应修改,
								且在 set 中要引起计算时所依赖的数据发生变化。
		-->
    <!-- 准备一个容器 -->
    <div id="root">
        姓:<input type="text" v-model="firstNmae"><br/>
        名:<input type="text" v-model="lastNmae"><br/>
        全名:<span>{{fullName}}</span>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
        el: '#root',
        data: {
            firstNmae: '张',
            lastNmae: '三'
        },
        computed:{
			// 完整写法
            /*fullName:{
                // 当有人读取 fullName 时,get就会被调用,且返回值就作为 fullName 的值
                // get 的调用时机:
                //     初次读取 fullName 时
                //     所依赖的数据发生变化时 
                get(){
                  console.log(this) // 此处的 this 是 vm 
                  return this.firstNmae + '-' + this.lastNmae
                },
				// set 的调用时机:当计算属性值,例如 fullName 修改时 
				set(newName){
					console.log(this) // 此处的 this 是 vm 
					const arr = newName.split('-');
					this.firstNmae = arr[0]
					this.lastNmae = arr[1]
				}
            }*/
			// 当确定计算属性不会被修改时,可以简写成如下形式
			fullName(){
				// console.log(this) // 此处的 this 是 vm 
              	return this.firstNmae + '-' + this.lastNmae
			}
        }
    })
</script> 
1.10 监视属性
1.10.1 天气案例-监视属性
<body>
    <!--
      监视属性 watch
        当被监视的属性变化时,回调函数自动调用,进行相关操作
        监视的属性必须存在才能进行监视
        监视的两种写法:
            new Vue 时传入 watch 配置
            通过 vm.$watch 监视
    -->
    <!-- 准备一个容器 -->
    <div id="root">
			<h1>今天天气很{{weather}}</h1> 
			<button @click="changeWeather">切换天气</button>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
			el: '#root',
			data: {
				isHot: true,
			},
			computed:{
				weather(){
					return this.isHot ? '炎热' : '凉爽'
				}
			},
			methods: {
				changeWeather(){
					this.isHot = !this.isHot;
				}
			},
			/*watch:{
				isHot:{
					immediate:true, // 初始化时让 handler 调用一次
					// handler 当 isHot 发生变化的时候就调用一次
					handler(newValue, oldValue){
						console.log('isHot被修改了', newValue, oldValue)
					},
          // 当监视属性中只有一个 handler 函数时,可以简写
          isHot(newValue, oldValue){
		        console.log('isHot被修改了', newValue, oldValue) 
	        }
				}
			}*/
    })
/*	vm.$watch('isHot', {
		immediate:true, // 初始化时让 handler 调用一次
		// handler 当 isHot 发生变化的时候就调用一次
		handler(newValue, oldValue){
			console.log('isHot被修改了', newValue, oldValue)
		}
	})*/
  // 当监视属性中只有一个 handler 函数时,可以简写
  vm.$watch('isHot', function(newValue, oldValue){
		console.log('isHot被修改了', newValue, oldValue) 
	})
</script> 
1.10.2 天气案例-深度监视
<body> 
		<!--
				深度监视
					Vue 中的 watch默认不监测对象内部值的改变(一层)
					配置 deep:true 可以监测对象内部值改变(多层)
				备注:
					Vue 自身可以监测对象内部值的改变,但Vue 提供的watch 默认不可以 
					使用 watch 时根据数据的具体结构,决定是否采用深度监视 
		-->
    <!-- 准备一个容器 -->
    <div id="root">
			<h1>今天天气很{{weather}}</h1> 
			<button @click="changeWeather">切换天气</button>
			<hr/>
			<h1>a 的值是: {{numbers.a}}</h1>
			<button @click="numbers.a++">点我让a加1</button>
			<h1> b值是: {{numbers.b}}</h1>
			<button @click="numbers.b++">点我让b加1</button>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示

    const vm = new Vue({
			el: '#root',
			data: {
				isHot: true,
				numbers:{
					a: 1,
					b: 1
				}
			},
			computed:{
				weather(){
					return this.isHot ? '炎热' : '凉爽'
				}
			},
			methods: {
				changeWeather(){
					this.isHot = !this.isHot;
				}
			},
			watch:{
				isHot:{
					// immediate:true, // 初始化时让 handler 调用一次
					// handler 当 isHot 发生变化的时候就调用一次
					handler(newValue, oldValue){
						console.log('isHot被修改了', newValue, oldValue)
					}
				},
				// 监视多级结构中的某个属性的变化
			/*	'numbers.a':{
					handler(){
						console.log('a被修改了')
					}
				}, */
				// 监视多级结构中的所有属性的变化
				numbers:{
					deep: true, // 开启深度监视
					handler(){
						console.log('numbers被修改了')
					}
				}
			}
    })
</script> 
1.10.3 姓名案例-watch实现
<body> 
  <!--
    computed 和 watch 之间的区别:
      computed 能完成的功能,watch都可以完成;
      watch 能完成的功能,computed 不一定能完成,例 watch 可以进行异步操作。
    两个重要的小原则:
      所有被 Vue 管理的函数,最好写成普通函数,这样 this 的指向才是 vm 或 组件实例对象
      所有不被 Vue 管理的函数 (定时器的回调函数,ajax 的回调函数,promise 的回调函数等)
        最好写成箭头函数,这样 this 的指向才是 vm 或 组件实例对象
  -->
    <!-- 准备一个容器 -->
    <div id="root">
        姓:<input type="text" v-model="firstNmae"><br/>
        名:<input type="text" v-model="lastNmae"><br/>
        全名:<span>{{fullName}}</span>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
        el: '#root',
        data: {
            firstNmae: '张',
            lastNmae: '三',
            fullName: '张-三'
        }, 
        watch:{
          firstNmae(value){
            setTimeout(() => {
              this.fullName = value + '-' + this.lastNmae
            }, 1000);
          },
          lastNmae(value){
            this.fullName = this.firstNmae + '-' + value
          }
        }
    })
</script> 
1.11 绑定样式
<style>
		.basic{ width: 400px; height: 100px; border: 1px solid black;}
		.happy{border: 4px solid red; background-color: rgba(255, 255, 0, 0.644);
			background: linear-gradient(30deg,yellow,pink,orange,yellow);}
		.sad{ border: 4px dashed rgb(2, 197, 2); background-color: gray; }
		.normal{ background-color: skyblue; }
		.atguigu1{ background-color: yellowgreen; }
		.atguigu2{ font-size: 30px; text-shadow:2px 2px 10px red; }
		.atguigu3{ border-radius: 20px; }
</style>
<body>
    <!--
      绑定样式:
        class 样式:
          :class="xxx", xxx 可以是字符串、对象、数组。
            字符串写法适用于:类名不确定,需要动态绑定;
            对象写法适用于:样式的个数不确定,名字也不确定;
            数组写法适用于:样式的个数确定,名字也确定,但要动态决定用不用。
        style 样式:
            :style="{fontSize: xxx}" 其中 xxx 是动态值;
            :style="[a, b]" , 其中 a、b 是样式对象。
     -->
    <!-- 准备一个容器 -->
    <div id="root">
    <!-- 绑定 class 样式 -- 字符串写法,适用于:样式的类名不确定,需要动态绑定 -->
    <div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br>

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

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

    <!-- 绑定 style 样式 -- 对象写法 -->
    <div class="basic" :style="styleObj">{{name}}</div> <br>

    <!-- 绑定 style 样式 -- 数组写法 -->
    <div class="basic" :style="styleArr">{{name}}</div>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
      el: '#root',
      data:{
        name:'凌宸',
        mood:'normal',
        classArr: ['atguigu1', 'atguigu2', 'atguigu3'],
        classObj:{
          atguigu1: false,
          atguigu2:false
        },
        styleObj:{
          fontSize: '40px',
          color: 'red',
        },
        styleArr:[
          { fontSize: '40px', color: 'red'},
          { backgroundColor: 'gray'}
        ],
      },
      methods:{
        changeMood(){
          const arr = ['happy', 'sad', 'normal']
          const index = Math.floor(Math.random() * 3)
          this.mood = arr[index]
        }
      }
    })
</script> 
1.12 条件渲染
<body>
    <!--
      v-if:
          写法:
              v-if="表达式"
              v-else-if="表达式"
              v-else="表达式"
          适用于:切换频率较低的场景;
          特点:不展示的 DOM 元素直接被移除;
          注意:v-if 可以和  v-else-if、v-else 一起使用,但要求结构不能被"打断"。
      
      v-show:
          写法:v-show="表达式"
          适用于:切换频率较高的场景;
          特点:不展示的 DOM 元素未被一出,仅仅是使用样式隐藏掉。

      备注:使用 v-if 时,元素可能无法获取到,而是用 v-show 一定可以获取到。
    -->
    <!-- 准备一个容器 -->
    <div id="root">
      <!-- 使用 v-show 做条件渲染 -->
      <!-- <h2 v-show="false">欢迎{{name}}</h2>
      <h2 v-show="1 === 1">欢迎{{name}}</h2> -->

      <!-- 使用 v-if 做条件渲染 -->
      <!-- <h2 v-if="false">欢迎{{name}}</h2>
      <h2 v-if="1 === 1">欢迎{{name}}</h2> -->

      <!-- v-else 和 v-else-if -->
      <div>此时 n 的值为 {{n}}</div>
      <div v-if="n === 1">1</div>
      <div v-else-if="n === 2">2</div>
      <div v-else-if="n === 3">3</div>
      <div v-else>其他</div>
      <button @click="n ++">点我 n + 1</button>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
        el: '#root',
        data:{
            name: '凌宸',
            n:0
        }
    })
</script> 
1.13 列表渲染
1.13.1 基本列表
<body>
    <!--
      v-for 指令:
          用于展示列表数据
          语法:v-for="(item, index) in xxx" :key="yyy"
          可遍历:数组(常用),对象,字符串(不常用),指定次数(不常用)
    -->
    <!-- 准备一个容器 -->
    <div id="root">
      <!-- 遍历数组 -->
      <h2>人员列表(遍历数组) 最常用</h2>
      <ul>
        <li v-for="(p,index) in persons" :key="index">
          {{p.name}} - {{p.age}}
        </li>
      </ul>
      <!-- 遍历对象 -->
      <h2>骑车信息(遍历对象)</h2>
      <ul>
        <li v-for="(value,k) in car" :key="k">
          {{k}} - {{value}}
        </li>
      </ul>
      <!-- 遍历字符串 -->
      <h2>遍历字符串</h2>
      <ul>
        <li v-for="(char,index) in str" :key="index">
          {{char}} - {{index}}
        </li>
      </ul>
      <!-- 遍历次数 -->
      <h2>遍历次数</h2>
      <ul>
        <li v-for="(number,index) in 6" :key="index">
          {{number}} - {{index}}
        </li>
      </ul>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    new Vue({
        el: '#root',
        data:{
          persons: [
            {id:'001', name:'张三', age: 18},
            {id:'002', name:'李四', age: 19},
            {id:'003', name:'王五', age: 20},
          ],
          car:{
            name: '奥迪A8',
            price:'70w',
            color:'黑色'
          },
          str:'hello'
        }
    })
</script> 
1.13.2 key的原理 (重要)

在这里插入图片描述
在这里插入图片描述

<body> 
    <!--
      面试题:react、vue 中的 key 有什么作用?(key 的内部原理)
          1.虚拟 DOM 中 key 的作用:
              key 是 虚拟 DOM 对象的标识,当状态中的数据发生变化时,
              Vue 会根据【新数据】生成【新的虚拟 DOM】。
              随后 Vue 进行【新虚拟 DOM】与【旧虚拟 DOM】的差异比较,比较规则如下
          2.对比规则:
              旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
                  若虚拟 DOM 中内容没变,直接使用之前的真实 DOM !
                  若虚拟 DOM 中内容变了,则生成新的真实 DOM,随后替换页面中之前的真实 DOM。
              旧虚拟 DOM 中未找到与新虚拟 DOM 相同的 key:
                  创建新的真实 DOM ,随后渲染到页面。
          3.用 index 作为 key 可能引发的问题:
              若对数据进行:逆序添加、逆序删除等破坏顺序操作
                  会产生没有必要的真实 DOM 更新 ==> 页面小贵没问题,但效率低。
              若结构中还包含输入类的 DOM:会产生错误 DOM 更新 ==> 界面有问题。
          4.开发中如何选择 key?
              最好使用每天数据的唯一标识作为 key,比如 id,手机号,邮箱,身份证号,学号等唯一值。
              如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
                  使用 index 作为 key 是没有问题的。    
    -->
    <!-- 准备一个容器 -->
    <div id="root">
      <!-- 遍历数组 -->
      <h2>人员列表(遍历数组) 最常用</h2>
      <button @click.once="add">点我添加老刘信息</button>
      <ul>
        <li v-for="(p,index) in persons" :key="p.id">
          {{p.name}} - {{p.age}}
          <input type="text">
        </li>
      </ul>   
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    new Vue({
        el: '#root',
        data:{
          persons: [
            {id:'001', name:'张三', age: 18},
            {id:'002', name:'李四', age: 19},
            {id:'003', name:'王五', age: 20},
          ], 
        },
        methods: {
          add(){
            const p = {id:'004', name:'老刘', age:30}
            this.persons.unshift(p)
          }
        },
    })
</script> 
1.13.3 列表过滤和排序
<body>  
    <div id="root">
      <!-- 遍历数组 -->
      <h2>人员列表</h2>
      <input type="text" placeholder="请输入名字" v-model="keyword">
      <button @click="sortType = 2">年龄升序</button>
      <button @click="sortType = 1">年龄降序</button>
      <button @click="sortType = 0">原顺序</button>
      <ul>
        <li v-for="(p,index) in fillPersons" :key="p.id">
          {{p.name}} - {{p.age}} - {{p.sex}}
        </li>
      </ul>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    new Vue({
        el: '#root',
        data:{
          keyword:'',
          sortType: 0, // 0 表示原顺序,1 降序, 2 升序
          persons: [
            {id:'001', name:'马冬梅', age: 31, sex: '女'},
            {id:'002', name:'周冬雨', age: 29, sex: '女'},
            {id:'003', name:'周杰伦', age: 20, sex: '男'},
            {id:'004', name:'温兆伦', age: 22, sex: '男'}
          ] 
        }, 
        computed:{ // 计算属性 实现 列表过滤
          fillPersons(){
            const arr = this.persons.filter((p) => {
              return p.name.indexOf(this.keyword) !== -1
            })
            // 判断是否需要排序
            if(this.sortType){
              arr.sort((p1, p2) => {
                return this.sortType === 2 ? p1.age - p2.age : p2.age - p1.age 
              })
            }
            return arr
          }
        }
    })
</script> 
1.13.4 更新时候的一个小bug
<body> 
    <!-- 准备一个容器 -->
    <div id="root">
      <!-- 遍历数组 -->
      <h2>人员列表</h2> 
      <button @click="updateMei">点我更新马冬梅信息</button> 
      <ul>
        <li v-for="(p,index) in persons" :key="p.id">
          {{p.name}} - {{p.age}} - {{p.sex}}
        </li>
      </ul>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
        el: '#root',
        data:{ 
          persons: [
            {id:'001', name:'马冬梅', age: 31, sex: '女'},
            {id:'002', name:'周冬雨', age: 29, sex: '女'},
            {id:'003', name:'周杰伦', age: 20, sex: '男'},
            {id:'004', name:'温兆伦', age: 22, sex: '男'}
          ] 
        }, 
        methods: {
          updateMei(){
            // 奏效
            // this.persons[0].name = '马老师'
            // this.persons[0].age = 50
            // this.persons[0].sex = '男'
            // 不奏效
            // this.persons[0] = {id:'001', name:'马老师', age: 50, sex: '男'}
            this.persons.splice(0, 1, {id:'001', name:'马老师', age: 50, sex: '男'})
          }
        },
    })
</script> 
1.13.5 Vue.set的使用
<body>
    <!-- 准备一个容器 -->
    <div id="root">
        <h1>学校信息</h1>
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
        <h1>学生信息</h1>
        <button @click="addSex">点我添加性别属性,默认值为男</button>
        <h2>学生姓名:{{student.name}}</h2>
        <h2 v-if="student.sex" >性别:{{student.sex}}</h2>
        <h2>学生年龄:真实年龄{{student.age.rAge}}, 对外年龄{{student.age.sAge}}</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" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
        el: '#root',
        data: {
          name: '南昌大学',
          address: '江西南昌',
          student:{
            name:'lc',
            age:{ rAge: 32, sAge: 28 },
            friends:[
              {name:'jack', age:28},
              {name:'curry', age:31}
            ]
          }
        },
        methods: {
          addSex(){
            // Vue.set(this.student, 'sex', '男')
            this.$set(this.student, 'sex', '男')
          }
        },
    })
</script> 
1.13.6 Vue监测数据原理总结
<style> * { margin-top: 10px; } </style>
<body>
<!--
    Vue 监视数据的原理:
        Vue 会监视 data 中所有层次的数据。

        如何监测对象中的数据?
            通过 setter 实现监视,且要在 new Vue 时就传入要监测的数据
            对象中后追加的属性,Vue 默认不做响应式处理
              	如需给后添加的属性作响应式,请使用如下的 API:
                	Vue.set(target, propertyName/index, value) 或
                  	this.$set(target, propertyName/index, value)
            
        如何监测数组中的数据?
            通过包裹数组更新元素的方法实现,本质就是做了两件事
                调用原生对应的方法对数组进行更新
                重新解析模板,进而更新页面

        在 Vue 修改数组中的某个元素一定要用如下方法:
            使用这些API:push(), pop(), shift(), unshift(), splice(), sort(), reverse()
            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="updateFirstHobbyName">修改第一个爱好为:开车</button><br>
        
        <h2>学生姓名:{{student.name}}</h2>
        <h2 v-if="student.sex" >性别:{{student.sex}}</h2>
        <h2>学生年龄:{{student.age}}</h2>
        <h2>朋友们</h2>
        <ul>
          <li v-for="(f,index) in student.friends" :key="index">
            {{f.name}} -- {{f.age}}
          </li>
        </ul>
        <h2>爱好</h2>
        <ul> 
          <li v-for="(h,index) in student.hobbies" :key="index">
            {{h}}
          </li>
        </ul>
      </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
        el: '#root',
        data: {
          student:{
            name:'lc',
            age: 18,
            friends:[
              {name:'jack', age:28},
              {name:'curry', age:31}
            ],
            hobbies:['篮球','骑行','吃喝玩乐']
          }
        },
        methods: {
          addSex(){
            // Vue.set(this.student, 'sex', '男')
            this.$set(this.student, 'sex', '男')
          },
          addFriend(){
            this.student.friends.unshift({name:'hello', age:22})
          },
          updateFirstFriendName(){
            this.student.friends[0].name = '张三'
          },
          addHobby(){
            this.student.hobbies.push('学习')
          },
          updateFirstHobbyName(){
            // this.student.hobbies.splice(0, 1, '开车')
            // Vue.set(this.student.hobbies, 0 , '开车')
            this.$set(this.student.hobbies, 0 , '开车')
          }
        },
    })
</script> 
1.14 收集表单数据
<body>
    <!--
      收集表单数据
        若:<input type="text"/>, 则 v-model 收集的是 value值,用户输入的就是 value 值。
        若:<input type="radio"/>, 则 v-model 收集的是 value值,且要给标签配置 value 值。
        若:<input type="checkbox"/>, 
            没有配置 input 的 value 属性,那么收集的就是 checked (勾选 or 未勾选,布尔值)
            配置 input 的 value 属性:
                v-model 的初始值是非数组,那么收集的就是 checked (勾选 or 未勾选,布尔值)
                v-model 的初始值是数组,那么收集的就是 value 组成的数组
        备注:v-model 的三个修饰符:
            lazy:失去交点再收集数据;
            number:输入字符串转为有效的数字;
            trim:输入首尾空格过滤。
    -->
    <!-- 准备一个容器 -->
    <div id="root">
        <form>
            账号:<input type="text" v-model.trim="account"> <br>
            密码:<input type="password" v-model="password"> <br>
            年龄:<input type="number" v-model.number="age"> <br>
            性别:
            <input type="radio" name="sex"  v-model="sex" value="male"><input type="radio" name="sex"  v-model="sex" value="female"><br>
            掌握语言:
            <input type="checkbox" v-model="lang" value="cpp"> C++
            <input type="checkbox" v-model="lang" value="java"> Java
            <input type="checkbox" v-model="lang" value="python"> Python <br>
            所属校区:
            <select v-model="city">
                <option value="">请选择校区</option>
                <option value="qianhu">前湖校区</option>
                <option value="qingshanhu">青山湖校区</option>
                <option value="fuzhou">抚州校区</option>
                <option value="gongqingcheng">共青城校区</option>
            </select> <br><br>
            其他信息:
            <textarea v-model.lazy="other"></textarea> <br> <br>
            <input type="checkbox" v-model="agree">阅读并接受<a href="http://www.baidu.com">《用户协议》</a>
            <br> <br> <button>提交</button> 
          </form>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    new Vue({
      el: '#root',
      data:{
        account: '',
        password: '',
        age:19,
        sex:'female',
        lang:[],
        city: 'qianhu',
        other:'',
        agree:''
      }
    })
</script> 
1.15 过滤器
<!-- 引入 Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript" src="../js/dayjs.min.js"></script> 
<body>
    <!-- 
			过滤器:
				定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
				语法:
						1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
						2.使用过滤器:{{ xxx | 过滤器名}}  或  v-bind:属性 = "xxx | 过滤器名"
				备注:
						1.过滤器也可以接收额外参数、多个过滤器也可以串联
						2.并没有改变原本的数据, 是产生新的对应的数据
		-->
    <!-- 准备一个容器 -->
    <div id="root">
        <h2>显示格式化后的时间</h2>
        <!-- 计算属性实现 -->
        <h2>现在是:{{fmtDate}}</h2>
        <!-- methods 实现 -->
        <h2>现在是:{{getFmtTime()}}</h2>
        <!-- 过滤器实现 -->
        <h2>现在是:{{time | timeFormatter}}</h2>
        <!-- 过滤器实现(传参) -->
        <h2>现在是:{{time | timeFormatter('YYYY-MM-DD')}}</h2>
        <!-- 过滤器串联 -->
        <h2>现在是:{{time | timeFormatter('YYYY-MM-DD') | mySlice}}</h2>
    </div>
    <div id="root2">
      <h2>{{msg | mySlice}}</h2>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    // 配置全局过滤器
    Vue.filter('mySlice', function(value){
      console.log(value)
      return value.slice(0, 4)
    })
    new Vue({
      el: '#root',
      data:{ 
          time: 1621561377603, // 时间戳
          msg:'你好哇!凌宸'
      },
      computed:{
        fmtDate(){
          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:{
        timeFormatter(value, formatter = "YYYY年MM月DD日 HH:mm:ss"){
          return dayjs(value).format(formatter) 
        },
        // mySlice(value){
        //   return value.slice(0,4)
        // }
      }
    })

    new Vue({
			el:'#root2',
			data:{
				msg:'你好哇!凌宸'
			}
		})
</script> 
1.16 内置指令
1.16.1 v-text 及之前出现过的内置指令
<body>
    <!--
        v-bind : 单向绑定解析表达式,可简写为 :xxx
        v-model : 双向数据绑定
        v-for : 遍历数组、字符串、对象、循环次数
        v-on : 绑定事件监听,可简写为 @
        v-if : 条件渲染(动态控制结点是否存在)
        v-else : 条件渲染(动态控制结点是否存在)
        v-show : 条件渲染(动态控制结点是否展示)
        v-text 指令:
            作用:想起所在的节点中渲染文本内容;
            与插值语法的区别:v-text 会替换节点中的内容,{{xx}} 则不会。
    -->
    <!-- 准备一个容器 -->
    <div id="root">
        <h1>{{name}}</h1>
        <h1 v-text="name"></h1>
        <h1 v-text="str"></h1>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    new Vue({
        el:'#root',
        data:{
            name:'张三',
            str:'<h1>你好啊</h1>'
        }
    })
</script> 
1.16.2 v-html,v-cloak,v-once,v-pre
<body>
    <!--
        v-html 指令:
            作用:想指定结点中渲染包含 html 结构的内容
            与插值语法的区别
                v-html 会替换掉结点中所有的内容,{{xx}} 则不会;
                v-html 可以识别 html 结构。
            严重注意:v-html 有安全性问题
                在网站上动态渲染任意 HTML 是非常危险的,容易导致 xss 攻击;
                一定要在可信的内容是哪个使用 v-html,永远不要在用户提交的内容上使用。
        v-cloak 指令:
            本质是一个特殊属性,Vue 实例创建完毕并接管容器后,会删掉 v-cloak 属性;
            使用 css 配合 v-cloak 可以解决网速慢时页面展示出 {{xxx}} 的问题。
				防止闪现, 与css 配合: [v-cloak] { display: none }
        v-once 指令:
            v-once 所在结点在初次动态渲染后,就视为静态内容了;
            以后数据的改变不会引起 v-once 所在结构的更新,可以用于优化性能。
        v-pre 指令:
            跳出其所在的结点的编译过程;
            可利用它跳过没有使用指令语法、没有使用插值语法的结点,会加快编译。
    -->
    <!-- 准备一个容器 -->
    <div id="root">
        <h1>{{name}}</h1>
        <h1 v-html="str"></h1>
        <h1 v-once>初始化的 n 的值为: {{n}}</h1>
        <h1>当前的 n 的值为: {{n}}</h1>
        <button @click="n ++">点我让 n + 1</button>
        <h1 v-pre>Vue 其实很简单</h1> 
        <h1 v-pre>初始化的 n 的值为: {{n}}</h1>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    new Vue({
        el:'#root',
        data:{
            name:'张三',
            str:'<h1>你好啊</h1>',
            n: 1
        }
    })
</script> 
1.17 自定义指令
<body>
    <!-- 准备一个容器 -->
    <!--
        需求一:定义一个 v-big 指令,和 v-text 指令类似,但会把绑定的数值放大 10 倍
        需求二:定义一个v-fbind 指令,和 v-bind 功能类似,但可以让其所绑定的 input 元素默认获取焦点
        自定义指令总结:
          定义语法:
            局部指令:
              new Vue({                           new Vue({
                directives:{指令名:配置对象}  或    directives:指令名(){}
              })                                  })
            全局指令:
              Vue.directive(指令名,配置对象)  或 Vue.directive(指令名,回调函数)

          配置对象中常用的 3 个回调:
            bind: 指令与元素成功绑定时调用;
            inserted: 指令所在元素被插入页面时调用;
            update: 指令所在模板被重新解析时调用。

          备注:
            指令定义时不需要加 v- , 但使用时需要加 v- ;
            指令名如果是多个单词,要是用 kebab-case 命名方式,不要用 camelCase命名。
      -->
    <div id="root">
      <h1>当前的 n 值为:<span v-text="n"></span></h1>
      <h1>放大 10 倍之后的 n 值为:<span v-big="n"></span></h1>
      <button @click="n++">点我 n + 1</button>
      <hr>
      <input type="text" v-fbind="n">
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    // 自定义全局指令写法
    // Vue.directive('big', function(element, binding){
    //   element.innerText = binding.value * 10
    // },)
    new Vue({
      el:'#root',
      data:{
        n: 1,
      },
      directives:{
        // big 函数何时被调用:指令与元素初次绑定时;指定所在的模板重新解析时。
        // 函数式写法相当于只实现 bind() 和 update()
        big(element, binding){
            element.innerText = binding.value * 10
        },
        fbind:{
          // 指令与元素初次绑定时调用
          bind(element, binding){
            element.value = binding.value
          },
          // 指令所在元素被插入页面时调用
          inserted(element, binding){
            element.focus()
          },
          // 指定所在的模板重新解析时调用
          update(element, binding){
            element.value = binding.value
          }
        }
      }
    })
</script> 
1.18 生命周期
1.18.1 引出生命周期
<body>
    <!-- 
      生命周期:
        又名:生命周期回调函数、生命周期函数、生命周期钩子;
        是什么:Vue 在关键时刻帮我们调用的一些特殊名称的函数;
        生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的;
        生命周期函数中国的 this 指向是 vm 或 组件实例对象。
     -->
    <div id="root">
      <h1 :style="{opacity}">你好啊,凌宸</h1>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    new Vue({
      el: '#root',
      data: {
        opacity: 1
      },
      // Vue 完成模板的解析并把 初始的真实 DOM 放入页面后(挂在完毕) 调用 mounted
      mounted() {
        setInterval(() => {
          this.opacity -= 0.01
          if(this.opacity <= 0) this.opacity = 1
        }, 16)
      },
    })
</script> 
1.18.2 生命周期流程

在这里插入图片描述

<body> 
    <div id="root">
      <h1 :style="{opacity}">此时的 n 的值为: {{n}}</h1>
      <button @click="add">点我 n + 1</button>
      <button @click="bye">点我销毁 vm</button>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    const vm = new Vue({
      el: '#root',
      // template: `
      //   <div>
      //     <h1>此时的 n 的值为: {{n}}</h1>
      //     <button @click="add">点我 n + 1</button>
      //   </div>
      // `,
      data: {
        n: 1,
        opacity: 1
      },
      methods: {
        add(){ this.n ++ },
        bye(){
          console.log('bye')
          this.$destroy()
        }
      },
      beforeCreate() { console.log('beforeCreate') },
      created() { console.log('created') },
      beforeMount() { console.log('beforeMount') },
      mounted() {  console.log('mounted') },
      beforeUpdate() { console.log('beforeUpdate')  },
      updated() { console.log('updated') },
      beforeDestroy() { cosole.log('beforeDestroy') },
      destroyed() { cosole.log('destroyed') },
    })
</script> 
1.18.3 生命周期总结
<body>
    <!-- 
        常用的生命周期钩子:
          mounted: 发送 ajax 请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
          beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】

        关于销毁 Vue 实例:
          销毁后借助 Vue 开发者工具看不到任何信息;
          销毁后自定义事件会失效,但原生 DOM 事件仍然有效;
          一般不会在 beforeDestroy 操作数据,因为即便操作数据,也不会触发更新流程。
     -->
    <div id="root">
      <h1 :style="{opacity}">你好啊,凌宸</h1>
      <button @click="opacity = 1">点我透明度设置为 1</button>
      <button @click="stop">点我停止变换</button>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    new Vue({
      el: '#root',
      data: {
        opacity: 1
      },
      methods: {
        stop(){
          console.log('stop')
          this.$destroy()
        }
      }, 
      mounted() {
        this.timer = setInterval(() => {
          this.opacity -= 0.01
          if(this.opacity <= 0) this.opacity = 1
        }, 16)
      },
      beforeDestroy() {
        clearInterval(this.timer)
      },
    })
</script> 
   n: 1,
    opacity: 1
  },
  methods: {
    add(){ this.n ++ },
    bye(){
      console.log('bye')
      this.$destroy()
    }
  },
  beforeCreate() { console.log('beforeCreate') },
  created() { console.log('created') },
  beforeMount() { console.log('beforeMount') },
  mounted() {  console.log('mounted') },
  beforeUpdate() { console.log('beforeUpdate')  },
  updated() { console.log('updated') },
  beforeDestroy() { cosole.log('beforeDestroy') },
  destroyed() { cosole.log('destroyed') },
})
```
1.18.3 生命周期总结
<body>
    <!-- 
        常用的生命周期钩子:
          mounted: 发送 ajax 请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
          beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】

        关于销毁 Vue 实例:
          销毁后借助 Vue 开发者工具看不到任何信息;
          销毁后自定义事件会失效,但原生 DOM 事件仍然有效;
          一般不会在 beforeDestroy 操作数据,因为即便操作数据,也不会触发更新流程。
     -->
    <div id="root">
      <h1 :style="{opacity}">你好啊,凌宸</h1>
      <button @click="opacity = 1">点我透明度设置为 1</button>
      <button @click="stop">点我停止变换</button>
    </div>
</body>
<script type="text/javascript" >
    Vue.config.productionTip = false; // 组织 Vue 在启动时生成生产提示
    new Vue({
      el: '#root',
      data: {
        opacity: 1
      },
      methods: {
        stop(){
          console.log('stop')
          this.$destroy()
        }
      }, 
      mounted() {
        this.timer = setInterval(() => {
          this.opacity -= 0.01
          if(this.opacity <= 0) this.opacity = 1
        }, 16)
      },
      beforeDestroy() {
        clearInterval(this.timer)
      },
    })
</script> 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lingchen0522

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值