Vue笔记

vue简介

播放音乐 看博客 岂不美哉

1.vue是什么

一套用于构建用户界面渐进式javascript框架

构建用户界面:拿到的数据转换为用户可以看到的数据

渐进式:vue可以自底向上逐层用 从一个轻量小巧的库逐渐递进到使用各式各样的vue插件

2.vue开发者(老二次元了,哈哈

2013 受到Angular的启发,尤雨溪开发出了一款轻量框架Seed同年12月,Seed更名为vue 版本号0.6.0
2014 vue正式对外发布,版本0.8.0
2015 10月27日,正式发布vue1.0.0 Evangelion(新世纪福音战士)
2016 10月1日,正式发布vue2.0.0 Ghost in the Shell(攻壳机动队)
2020 10月27日,正式发布vue1.0.0 One Piece(海贼王)

3.vue的特点

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

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

声明式编码和命令式编码区别

1.命令式:举个例子就是说一下做一下不说就不做

2.声明式:举个例子就是口有点干,说一声口有点干 然后就会有人给我泡茶倒水端到我跟前

4.虚拟DOM

  • 虚拟DOM就是内存中的一个数据vue可以最后转换成真实的DOM

把代码转换为虚拟的DOM然后虚拟DOM转换为真实DOM,如果数据中新添加了赵六,vue会创建一个新的DOM,然后会跟旧的DOM作比较(通过Diff算法)没有改变的数据直接复用,然后转换为页面的真实DOM

vue开发环境

1.引入vue文件

<script type="text/javascript" src="https://unpkg.com/vue"></script><!--这里引入的是vue的cnd->

2.下载插件

在浏览器扩展里面搜索Vue.js devtools插件 下载(注意:在详细信息里面勾选 允许访问文件 URL选项)

vue基础语法

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>
</head>
<!-- 引入vue.js文件 -->
<script src="../static/js/vue.js"></script>
<body>
    <!--
        容器 
        vue实例和容器是一一对应的
        {{}}插值语法 不仅可以读取到vue实例中的data里的属性 也可以写入js表达式比如:{{1+1}}
    -->
    <div id="root">
        <h1>{{name}}</h1>
    </div>



    <script>
    //创建vue实例对象  
    new Vue({
        //el指定当前vue实例为当前那个容器服务,值通常为css选择器字符串
        el: "#root",
        //data用于存储数据 数据供el提供的容器使用
        data: {
            name: "初始vue",
        },
    })
    </script>
</body>
</html>
  • 当vue开始工作的时候把容器拿过来解析,解析容器里有没有vue的语法,里面有一个插值语法,然后找到name把属性值赋值给容器里面的name,然后生成了全新的一个容器,在把解析完的容器放到页面当中

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>
<!-- 引入vue.js文件 -->
<script src="../static/js/vue.js"></script>
<body>
    <div id="root">
        <h1>两年前</h1>
        <h2>{{name}}</h2>
        <h1>两年后</h1>
        <!-- 指令语法:也可以简写为:href 在属性前面加:就是v-bind指令语法-->
        <a v-bind:href="onepicec.url">{{onepicec.name}}</a>
    </div>

    <script>
     new Vue({
        el: "#root",
        data: {
          name: "梅利号",
          onepicec: {
              name: "万里阳光号",
              sex: "男",
              url: "https://one-piece.com/",
          },         
        },
     });   
    </script>
</body>
</html>

1.插值语法:

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

2.指令语法:

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

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>
<!-- 引入vue.js文件 -->
<script src="../static/js/vue.js"></script>
<body>
        <div id="root">
            单项绑定:<input type="text" v-bind:value="name">
            <br/>
            双向绑定:<input type="text" v-model:value="name">
            <br>
            单项绑定简写:<input type="text" :value="name">
            <br/>
            双向绑定简写:<input type="text" v-model="name">
        </div>

        <script>
            new Vue({
                el: "#root",
                data: {
                    name: "海贼王",
                },
            });
        </script>
</body>
</html>

vue中的两种绑定方式

1.单项绑定

数据只能从data流向页面

2.双向绑定

数据不仅能从data流向页面 而且还可以从页面流向data

双向绑定一般应用在表单元素上

v-model默认绑定的就是value 所以可以简写为v-model

3.el和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>
</head>
<!-- 引入vue.js文件 -->
<script src="../static/js/vue.js"></script>
<body>
    <div id="root1">
        <h1>{{name}}</h1>
    </div>
    <div id="root2">
        <h1>{{name}}</h1>
    </div>
    
    <script>
        //第一种el和data的写法
        new Vue({
           el: "#root1",
        
           data: {

              name: "火影忍者", 

           },
        });
        //第二种el和data的写法
        const vm=new Vue({
        
           data(){
            return{
                name: "鬼灭之刃"
            }
           }
        });
        vm.$mount("#root2");
    </script>
</body>
</html>

el的两种

1.newVue的时候被指el属性

2.先创建vue实例然后在通过vm.$mount("#root2")指定el的值

data的两种

1.对象式

2.函数式

3.注意:

  • data以后学习到组件的时候必须使用函数时不然会报错

  • vue管理的函数不要写箭头函数不然this指向就不是vu实例了

4.MVVM

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

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

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

5.数据代理

1.回顾object.defineProperty

<!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>
<script src="../static/js/vue.js"></script>
<body>
    <script>
        let nums=18;
        
        let arrays={
            name: "张三",
            sex: "男",
        };

        Object.defineProperty(arrays,'age',{
            /*
            value: 18,
            // 设置属性是否可以枚举
            enumerable:true,
            //设置属性是否可以被修改
            writable:true,
            // 设置属性是否可以删除
            configurable:true,
            */
           // 当读取age属性 就调用get方法    
           get(){
            console.log("读取了get")
            return age=nums;
           },
           // 当修改age属性 就调用set方法   
           set(value){
            console.log("修改了age")
            return nums=value;
           },
        });
        for(let array in arrays){
            console.log(array);
        };
    </script>
</body>
</html>

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

2.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>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
    <div id="root">
        <h1>{{name}}</h1>
        <h1>{{sex}}</h1>
    </div>

    <script>
        let datavm={
            name: "蒙奇.D.路飞",
            sex: "女",
        }

        const vm = new Vue({
            el: "#root",
            data: datavm,
        });
    </script>
</body>
</html>

比较_data是否是data

vm._data === datavm
true

vue中的数据代理

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

好处

更加方便的操作data里面的数据

基本原理

通过Object.defineProperty把data对象中所以的属性添加到vm对象中,为每一个添加到vm身上的属性添加getter/setter
通过getter/setter,内部去操作data中对应的属性

事件处理

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>
</head>
<script src="../static/js/vue.js"></script>
<body>
    <div id="root">
        <h1>{{name}}</h1>
        <button v-on:click="showInfo1()">梅利</button>
        <button @click="showInfo2($event,666)">桑尼</button>

    </div>

    <script>

    const vm=new Vue({
        el: "#root",    
        data: {
            name: "梅利号"
        },
        methods: {
            showInfo1(){
                alert("你好!梅利号");
            },
            showInfo2(event,nums){
                alert("你好!万里阳光号"+nums);
                console.log(event);
            },
        },
        
    });

    </script>
</body>
</html>
  • v-on:事件 可以简写为@事件

  • 事件的回调需要配置在methods对象中

2.事件修饰符

  • 修饰符
    prevent 阻止事件的默认事件
    stop 阻止冒泡
    once 事件只触发一次
    captrue 事件捕获是触发
    self 操作的是当前的事件才触发
    passive事件的默认行为立即执行
<!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>
<script src="../static/js/vue.js"></script>
<style>
    *{
        margin-top: 40px;
    }
    .box{
        width: 100%;
        height: 80px;
        background-color: aquamarine;
    }
    .box1{
        width: 100%;
        height: 80px;
        background-color: rgb(173, 58, 38);
    }
    .box2{
        width: 100%;
        height: 30;
        background-color: rgb(15, 37, 163);
    }
    .box3{
        width: 200px;
        height: 300px;
        overflow: auto;
    }
    .box3 >li {
        width: 200px;
        height: 100px;
        background-color: blue;
    } 
</style>
<body>
   
    <div id="root">
        <a href="https://www.bilibili.com" @click.prevent="showInfo()">白胡子</a>

        <div class="box" @click="showInfo">
            <button @click.stop="showInfo">冒泡</button>
        </div>

        <button @click.once="one">罗杰</button>

        <div class="box1" @click.capture="two(1)">
            div1
            <div class="box2" @click="two(2)">
                div2
            </div>
        </div>

        <div class="box" @click.self="there">
            <button @click="there">事件</button>
        </div>
        <!--wheel 鼠标滚轮触发事件-->
        <!--scroll 滚动条事件-->
        <ul @scroll.passvie="four" class="box3">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>

    </div>

    <script>
        new Vue({
           el: "#root",
           methods: {

           showInfo(){
            alert("one pirece 是真实存在的");
           }, 
           one(){
            alert("我的宝藏都放在哪里了去寻找吧");
           },
           two(a){
            console.log(a);
           },
           there(event){
            console.log(event.target);
           },
           four(){

            for (let i = 0; i < 100000; i++) {
               console.log("one pirece")
                
            }

           },

           },     
        });
    </script>
</body>
</html>

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>
<script src="../static/js/vue.js"></script>
<body>
    <div id="root">
        <input type="text" placeholder="输入数字" value="" @keydown.enter.y="showInfo"/>
    </div>

    <script>

        new Vue({
            el: "#root",
            methods: {
                showInfo(event){
                    // keyCode打印键盘的编码 key打印键盘名字
                    console.log(event.keyCode+"------------"+event.key);
                    console.log(event.target.value);
                },
            },
        })

    </script>
</body>
</html>
  • keydown事件 按下去触发事件
  • keyup事件 按下去不触发 然后弹上来触发事件
  • 回车 => enter
  • 删除 => delete
  • 退出 => esc
  • 空格 => space
  • 换行 => tab(特殊配合keydown使用 这个键会切换焦点)
  • 上 => up
  • 下 => down
  • 左 => left
  • 右 => right
  • 大写切换必须使用两个字母首字母小写中间用 - 拼接
  • Vue.config.keycodes.huiche=13 自定义键名

计算属性

1.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>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
    <div id="root">
        姓:<input type="text" v-model="firstName"/><br/>
        名:<input type="text" v-model="latsName"/><br/>
        <h1>{{ fullName() }}</h1><br/>
    </div>
    
    <script>
        new Vue({
            el: "#root",
            data: {
                firstName: "张",
                latsName: "三",  
            },
            
            methods: {
                fullName(){
                    return this.firstName+"-"+this.latsName;
                }
            },
            
        })
    </script>
</body>
</html>

2.computed计算

<!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>
<script src="../static/js/vue.js"></script>
<body>

    <div id="root">
        姓:<input type="text" v-model="firstName"/><br/>
        名:<input type="text" v-model="latsName"/><br/>
        <h1>{{ fullName }}</h1><br/>
    </div>
    
    <script>
        new Vue({
            el: "#root",
            data: {
                firstName: "张",
                latsName: "三",  
            },
            computed:{
                fullName:{

                    get(){
                        // 返回值会作为fullName的值
                        return this.firstName+"-"+this.latsName;

                    }

                },
            },
            /*简介写法 只读不改的情况下使用简写方式
            fullName(){ 
                // 返回值会作为fullName的值
                return this.firstName+"-"+this.latsName;
            },*/
            
        })
    </script>
</body>
</html>

计算属性

  • 定义:要用的属性不存在 要通过已有属性计算得来

  • 原理:借助了底层的object.defineproperty方法提供的getter/setter

  • get函数什么使用调用

    1.初次读取的时候调用一次

    2.当依赖的数据发生变化是在调用一次

  • 更methods相比内部有缓存机制(服用) 效率更高 调式方便

  • 计算属性最终会出现在vue的实例上 直接读取就可以使用

监视属性

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>
</head>
<script src="../static/js/vue.js"></script>
<body>
    
    <div id="root">
        <h2>我是{{ isName }}</h2>
        <button @click="is()">切换人物</button>
    </div>
    
    <script>
        const vm = new Vue({
            el: "#root",
            data: {
                name:true,
            },
            
            computed:{
                isName(){
                    return this.name==true? "海贼王路飞" : "大剑豪索隆" ;    
                }
            },
            methods: {
                is(){
                    return this.name = !this.name;
                }        
            },
            // watch: {
            //     isName:{
            //         // 监视的属性发生变化时调用
            //         handler(newValue,oldValue){
            //             console.log("isName被修改了"+newValue+oldValue);
            //         }
            //     }
            // }
        })
        vm.$watch('isName',{
            handler(newValue,oldValue){
                console.log("isName被修改了"+newValue+oldValue);      
            }
        });
    </script>
</body>
</html>
  • 当监视属性变化时 回调函数自动调用

  • 监视的属性必须存在才能监视

  • 两种写法

  • 1.vue实例里面写入watch配置对象

    2.通过vm.$watch()监视

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>
<script src="../static/js/vue.js"></script>
<body>

    <div id="root">
        <h2>a:{{ numbers.a }}</h2>
        <button @click="(numbers.a)++">加</button>
        <h2>b:{{ numbers.b }}</h2>
        <button @click="(numbers.b)--">减</button>
        <button @click=" numbers={a:2000,b:3000}">替换numbers</button>
    </div>
    
    <script>
        const vm = new Vue({
            el: "#root",
            data: {
                numbers:{
                    a: 1,
                    b: 100,
                },
            },
            
            watch: {
                // 'numbers.a':{
                //     // 监视的属性发生变化时调用
                //     handler(newValue,oldValue){
                //         console.log("a被修改了"+newValue+"---"+oldValue);
                //     }
                // },
                // 'numbers.b':{
                //     // 监视的属性发生变化时调用
                //     handler(newValue,oldValue){
                //         console.log("b被修改了"+newValue+"---"+oldValue);
                //     }
                // }
                numbers:{
                    // 深度监视 可以监视多层属性
                    deep:true,
                    handler(newValue,oldValue){
                        console.log("numbers被修改了"+newValue+"---"+oldValue);
                    }
                },
            }
        })
    </script>
</body>
</html>
  • vue中的watch默认不监视对象内部的变化(一层)
  • 配置deep:true,可以监视对象内部变化(多层)
  • vue可以检测对象内部的变化,但是vue提供的watch默认不可以

监视属性简写

numbers(newValue,oldValue){
                    
    console.log("numbers被修改了"+newValue+"---"+oldValue);
                    
},

3.watch和computed的区别

<!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>
<script src="../static/js/vue.js"></script>
<body>

    <div id="root">
        姓:<input type="text" v-model="firstName"/><br/>
        名:<input type="text" v-model="latsName"/><br/>
        <h1>{{ fullName }}</h1><br/>
    </div>
   
    <script>
        new Vue({
            el: "#root",
            data: {
                firstName: "张",
                latsName: "三",  
                fullName:"张-三"
            },
            watch: {
                firstName(newValue){
                    //箭头函数没有this 往外找 找到了vue管理的firstName函数 所以当前this是vue
                    setTimeout(()=>{
                        this.fullName = newValue + "-" + this.latsName;
                    },2000);
                   
                },

                latsName(newValue){
                    this.fullName = this.firstName + "-" + newValue;
                },
            },
            
        })
    </script>
</body>
</html>

区别

  • 计算属性可以完成功能的监视属性都可以完成
  • 监视属性可以完成的功能 计算属性未必完成 计算属性- 异步操作

样式绑定

1.:class的绑定

<!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>
<script src="../static/js/vue.js"></script>
<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;
    }

    .onepiece1{
        background-color: yellowgreen;
    }
    .onepiece2{
        font-size: 30px;
        text-shadow:2px 2px 10px red;
    }
    .onepiece3{
        border-radius: 20px;
    }
</style>

<body>
    <div id="root">
        <!-- 绑定样式 ----- 字符串写法 适用于类名不确定 需要动态的指定 -->
        <div class="basic" :class="mood" @click="Mood()">{{name}}</div>
        <br/>
        <br/>
        <!-- 绑定样式 ----- 数组写法 适用于绑定的个数不确定 名字不确定 -->
        <div class="basic" :class="arrMood">{{name}}</div>
        <br/>
        <br/>
        <!-- 绑定样式 ----- 对象写法 适用于绑定的个数确定 名字确定 但要动态的决定要不要 -->
        <div class="basic" :class="objectMood">{{name}}</div>
        <br/>
        <br/>
        <!--  绑定样式 ----- 对象写法 -->
        <div class="basic" :style="objectStyle">{{name}}</div>
        <br/>
        <br/>
        <!--  绑定样式 ----- 数组写法 -->
        <div class="basic" :style="arrStyle">{{name}}</div>

    </div>

    <script>
        new Vue({
            el: "#root",
            data: {
                name: "One Piece",
                mood: "normal",
                arrMood:['onepiece1','onepiece2','onepiece3'],
                objectMood:{
                    onepiece1:true,
                    onepiece2:false,
                },
                objectStyle:{
                    fontSize: '50px',
                    color: 'red',
                },
                arrStyle:[
                    {fontSize:'40px'},
                    {color:'yellow'},
                ],

            },  
            methods: {
                Mood(){
                    const arr=['happy','sad','normal'];
                    const index = Math.floor(Math.random()*3);   
                    this.mood=arr[index];
                },
            },      
        });
    </script>
</body>
</html>

渲染

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>
</head>
<script src="../static/js/vue.js"></script>
<body>
    <div id="root">
        <h2>现在index的值为:{{index}}</h2>
        <button @click="index++">按钮加+</button>

        <!-- 
        v-show

        <h3 v-show="index===1">蒙奇.D.路飞</h3>
        <h3 v-show="index===2">罗罗诺亚.索隆</h3>
        <h3 v-show="index===3">文斯莫克.山治</h3>
        -->

        <!-- 
        v-if    

        <h3 v-if="index===1">蒙奇.D.路飞</h3>
        <h3 v-if="index===2">罗罗诺亚.索隆</h3>
        <h3 v-if="index===3">文斯莫克.山治</h3> 
        -->

        <!-- 
        v-if
        v-if-else    
        
        <h3 v-if="index===1">蒙奇.D.路飞</h3>
        <h3 v-else-if="index===1">罗罗诺亚.索隆</h3>
        <h3 v-else-if="index===3">文斯莫克.山治</h3> 
        -->
        <!-- template配合v-if使用 -->
        <template v-if="index===3">
            <h3>蒙奇.D.路飞</h3>
            <h3>罗罗诺亚.索隆</h3>
            <h3>文斯莫克.山治</h3>     
        </template>
    </div>
    

    <script>
        new Vue({
            el: "#root",
            data:{
                index:0,
            },
        });
    </script>
</body>
</html>

总结

  • v-if

    写法

    1. v-if='表达式'

    2. v-else='表达式'-if

    3. v-else='表达式'

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

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

    注意:v-if可以和v-else-if和v-else配合使用 但结构不能被打断

  • v-show

    写法:v-show='表达式'

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

    特点:不展示的DOM不移除而是隐藏

  • 使用v-if时 元素可能无法获取 而使用v-show一定能获取到

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>
<script src="../static/js/vue.js"></script>
<style>
    #root>ul>li{
        font-size: 20px;
        color: green;
        list-style-type: none;
        text-align: center;
    }
</style>
<body>
    <div id="root">
        <ul>
            <!--遍历数组-->
            <li v-for="(p,index) in persons">
                {{index}}-{{p.name}}-{{p.sex}}
            </li> 
            <hr />
            <!--遍历对象-->
            <li v-for="(value,key) of car">
                {{key}}:{{value}}
            </li> 
            <hr/>
            <!--遍历字符串-->
            <li v-for="(value,key) of Luffy">
                {{key}}:{{value}}
            </li>
            <hr/>
             <!--遍历数字-->
            <li v-for="(value,key) of 10">
                {{key}}:{{value}}
            </li>

        </ul>
    </div>
    <script>
        new Vue({
            el: '#root',
            data: {
                persons:[
                {id:001,name:'蒙奇.D.路飞',sex:'男'},
                {id:002,name:'罗罗诺亚.索隆',sex:'男'},
                {id:003,name:'文斯莫克.山治',sex:'男'},
                ],
                car:{
                    name:'万里阳光号',
                    type:'船',
                    money:'$100亿贝利',
                },   
                Luffy:"I'm Luffy, I'm the man who wants to be the pirate king", 
            },
        });
    </script>
</body>
</html>

总结

  1. 用于展示列表数据
  2. 语法:v-for="(item,index) in 遍历的数组"

3.key作用以及原理

<!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>
<script src="../static/js/vue.js"></script>
<style>
    #root>ul>li{
        font-size: 20px;
        color: green;
        list-style-type: none;
        text-align: center;
    }
</style>
<body>
    <div id="root">
        <ul>
            <button @click="add">添加</button>
            <!--遍历数组-->
            <li v-for="(p,index) in persons" :key="p.id">
                {{index}}-{{p.name}}-{{p.sex}}
                <input type="text"/>
            </li> 
            
        </ul>
    </div>
    <script>
        new Vue({
            el: '#root',
            data: {
                persons:[
                {id:001,name:'蒙奇.D.路飞',sex:'男'},
                {id:002,name:'罗罗诺亚.索隆',sex:'男'},
                {id:003,name:'文斯莫克.山治',sex:'男'},
                ],
            },
            methods: {
                add(){
                    const p = {id:'004',name:'娜美',sex:'女'};
                    this.persons.unshift(p);
                },
            },
        });
    </script>
</body>
</html>

总结

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


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

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


若虚拟DOM中内容没变, 直接使用之前的真实DOM 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM 旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到到页面
用index作为key可能会引发的问题:
若对数据进行逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低 若结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题 开发中如何选择key?
最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值
如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用index作为key是没有问题的

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>
</head>
<script src="../static/js/vue.js"></script>
<style>
    #root>ul>li{
        font-size: 20px;
        color: green;
        list-style-type: none;
    }
</style>
<body>
    <div id="root">
        <ul>
            <input type="text" v-model="keyModel"/>
            <!--遍历数组-->
            <li v-for="(p,index) in filterArrs" :key="p.id">
                {{index}}-{{p.name}}-{{p.sex}}
            </li> 
            
        </ul>
    </div>
    <script>
        new Vue({
            el: '#root',
            data: {
                persons:[
                {id:001,name:'蒙奇D路飞',sex:'男'},
                {id:002,name:'哥儿D艾斯',sex:'男'},
                {id:003,name:'哥儿罗杰',sex:'男'},
                {id:003,name:'杰斯',sex:'男'},
                ],
                keyModel:'',
                filterArr: [],
            },
            //监视属性
            // watch:{
            //     keyModel:{
            //         immediate:true,
            //         handler(newValue){
            //             this.filterArr = this.persons.filter((p)=>{
            //                 return p.name.indexOf(newValue)!==-1;
            //             });
            //         },
            //     },
            // },
            //计算属性 
            computed:{
                // 初始化的时候调用 依赖的数据发生变化再次调用
                filterArrs(){
                    return this.persons.filter((p)=>{
                        return p.name.indexOf(this.keyModel) !== -1;
                    })
                }
            },
        });
    </script>
</body>
</html>

列表排序

            computed:{
                // 初始化的时候调用 依赖的数据发生变化再次调用
                filterArrs(){
                    const arr = this.persons.filter((p)=>{
                        return p.name.indexOf(this.keyModel) !== -1;
                    })
                    arr.sort((p1,p2)=>{
                        if(this.sortType){
                            return this.sortType !== 1 ? p1.id-p2.id : p2.id-p1.id
                        }
                    })
                    return arr
                } 
            },

数据监视

1.数据监视

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue数据监视</title>
		<style>
			button{
				margin-top: 10px;
			}
		</style>
		<script type="text/javascript" src="../static/js/vue.js"></script>
	</head>
	<body>
		<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>
			<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:'娜美',
					age:18,
					hobby:['抽烟','喝酒','烫头'],
					friends:[
						{name:'索隆',age:35},
						{name:'路飞',age:36}
					]
				}
			},
			methods: {
				addSex(){
                    Vue.set(this.student,'sex','女');
                },
                addFriend(){
                   this.student.friends.unshift({name:'乌索普',age:19});
                },
                updateFirstFriendName(){
                    this.student.friends[0].name="山治";
                },
                addHobby(){
                    this.student.hobby.push("贝利");
                },
                updateHobby(){
                    this.student.hobby.splice(0,1,'开车')
                },
                removeSmoke(){
                    this.student.hobby = this.student.hobby.filter((smk)=>{
                        // 过滤掉抽烟 不等于抽烟的全部返回
                        return smk!=='抽烟'
                    })

                },
			}
		})
	</script>
</html>

Vue监视数据的原理

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

如何监测对象中的数据?

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

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

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

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

如何监测数组中的数据

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

  1. 调用原生对应的方法对数组进行更新
  2. 重新解析模板,进而更新页面
  3. 在Vue修改数组中的某个元素一定要用如下方法:
//使用APl
push()、pop()、shift()、unshift()、splice()、sort()、reverse()
Vue.set() 或 vm.$set()

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

表单数据

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>
</head>
<script src="../static/js/vue.js"></script>
<style>
    *{
        margin-top: 20px;
    }
</style>
<body>
        <div id="root">

            <form @submit.prevent="demo">
            账号:<input type="text" v-model.trim="user.username">
            <br/>
            密码:<input type="password" v-model="user.password"> 
            <br/>
            <!-- 虽然v-model默认绑定的是value 但是要手动写value的值 -->
            性别:<input type="radio" v-model="user.sex" value="男">男
                 <input type="radio" v-model="user.sex" value="女">女
            <br>
            <!-- vue实例接收要用数组 还是要手动写value -->
            爱好:<input type="checkbox" v-model="user.hobby" value="海贼王">海贼王
                 <input type="checkbox" v-model="user.hobby" value="火影忍者">火影忍者
                 <input type="checkbox" v-model="user.hobby" value="鬼灭之刃">鬼灭之刃
                 <br/>
            所属校区:
				<select v-model="user.city">
					<option value="">请选择校区</option>
					<option value="dong">东海</option>
					<option value="xi">西海</option>
					<option value="bei">北海</option>
					<option value="nan">南海</option>
				</select>
                <br>
            其他信息:
            <textarea v-model.lazy="user.textform"></textarea>
            <br>
            <br>
            <input type="checkbox" v-model="user.public">阅读并接受<a href="http://www.bilibili.com">《用户协议》</a>
            <br>
            <input type="submit" value="提交">
            </form>
            
        </div>
        <script>
            new Vue({
                el: "#root",
                data: {
                    user:{
                    username: '',
                    password: '',     
                    sex: '男',   
                    hobby: [],    
                    city:'dong',
                    textform: '',
                    public: 'true',
                    },
                    
                },
                methods: {
                    demo(){
                        console.log(JSON.stringify(this.user));
                    }
                },
            });
        </script>


</body>
</html>

收集表单数据:

若:<input type="text"/> 则v-model收集的是value值,用户输入的内容就是value值
若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value属性
若:<input type="checkbox"/>
没有配置value属性,那么收集的是checked属性(勾选 or 未勾选,是布尔值)
配置了value属性:
v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
v-model的初始值是数组,那么收集的就是value组成的数组
v-model的三个修饰符:

lazy:失去焦点后再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤

过滤器

1.过滤器

<!DOCTYPE html>
<html>
	<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>
	</head>
    <script type="text/javascript" src="../static/js/vue.js"></script>
	<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js"></script>
	<body>
		<div id="root">
			<h2>时间</h2>
            <h3>当前时间戳:{{time}}</h3>
            <h3>转换后时间:{{time | timeFormater()}}</h3>
			<h3>转换后时间:{{time | timeFormater('YYYY-MM-DD HH:mm:ss')}}</h3>
			<h3>截取年月日:{{time | timeFormater() | mySlice}}</h3>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		//全局过滤器
		Vue.filter('mySlice',function(value){
			return value.slice(0,11)
		})
		new Vue({
            el:'#root',
            data:{
                time:1626750147900,
            },
			//局部过滤器
            filters:{
                // str当str不传参是默认就是"YYYY年MM月DD日 HH:mm:ss 如果传入参数就按参数的格式来
                timeFormater(value, str="YYYY年MM月DD日 HH:mm:ss"){
                    return dayjs(value).format(str)
                }
            }
        })
	</script>
</html>

事件转换的js文件

<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js"></script>

过滤器

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

  • 语法:

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

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

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

内置指令

1.v-text指令

目前学过的指令

  • v-bind 单项绑定表达式
  • v-model 双向数据绑定
  • v-on 绑定事件
  • v-for 遍历对象、数组、字符串
  • 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>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
    <div id="root">
        <div>{{name}}</div>
        <div v-text="name">onepiece</div>
    </div>

    <script>
        new Vue({
           el: "#root",
           data: {
              name: "海贼王", 
           }, 
        });
    </script>
</body>
</html>

v-text指令总结

  1. 向其所在的节点中渲染文本内容
  2. 于插值语法的区别 v-text会替换节点中的文本 插值语法不会

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>Document</title>
</head>
<script src="../static/js/vue.js"></script>
<body>
    <div id="root">
        <div v-html="h3">onepiece</div>
        <div v-html="a">onepiece</div>
    </div>

    <script>
        new Vue({
           el: "#root",
           data: {
              h3: "<h3>我是h3标签</h3>", 
              a: "<a href='https://bilibili.com?'+document.cookie>点击</a>",
           }, 
        });
    </script>
</body>
</html>

v-html指令总结

  • 作用
  1. 向指定节点渲染包含html结构的内容
  • 与插值语法的区别
  1. v-html会替换节点中所以的内容 {{}}插值语法不会

  2. v-html结构会识别html结构

  • v-html有安全性问题
  1. 在网站上动态渲染HTML是非常危险的 容器导致xss攻击

  2. 一定在可信的内容上使用v-html 不要用在用户提交的内容上

3.v-cloak指令

<!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>
<script src="../static/js/vue.js"></script>
<style>
    [v-cloak]{
        display: none;
    }
</style>
<body>
    <div id="root">
        <div v-cloak>{{name}}</div>
    </div>

    <script>
        new Vue({
           el: "#root",
           data: {
              name: "海贼王", 
           }, 
        });
    </script>
</body>
</html>

v-cloak指令总结(没有值)

  • 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
  • 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题

4.v-once指令

<!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>
<script src="../static/js/vue.js"></script>
<body>
    <div id="root">
       <h1 v-once>n的初始值为:{{n}}</h1> 
       <h1>n的值为:{{n}}</h1>
       <button @click="n++">n+1</button>
    </div>

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

v-once指令总结(没有值)

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

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

5.v-pre指令

<!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>
<script src="../static/js/vue.js"></script>

<body>
    <div id="root">
        <h1 v-pre>蒙奇.D.路飞</h1>
        <h1 v-pre>{{name}}</h1>
    </div>

    <script>
        new Vue({
           el: "#root",
           data: {
              name: "海贼王", 
           }, 
        });
    </script>
</body>
</html>

v-pre指令总结(没有值)

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

自定义指令

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>
</head>
<script src="../static/js/vue.js"></script>
<body>

    <div id="root">
        <h1>当前n的值:{{n}}</h1>
        <h1>n的10倍值:<span v-big="n"> </span></h1>
        <button @click="n++">n+1</button>
    </div>

    <script>
        new Vue({
            el: "#root",
            data: {
                n:1,
            },
            directives: {
                //big函数什么时候调用 指令与元素绑定成功时 指令所在的模板被重新解析时
                big(element,bigding){
                    console.log(element,bigding),
                    element.innerText=(bigding.value)*10

                }
            }
        });
    </script>
</body>
</html>
posted @ 2022-09-06 17:08  Mr邱  阅读(206)  评论(0)    收藏  举报