Vue2&3全面知识总结二

感兴趣的朋友可以去我的语雀平台进行查看更多的知识。
https://www.yuque.com/ambition-bcpii/muziteng

2. Vue核心二

2.1 计算属性与监视

2.1.1 计算属性

插值语法实现

<div id="app">
    姓:<input type="text" v-model="firstName"><br/>
    名:<input type="text" v-model="lastName"><br/>
    全名:<span>{{firstName}}--{{lastName}}</span>
</div>
<script>
    new Vue({
        el: "#app",
        data() {
            return {
                firstName: "张",
                lastName: "三"
            }
        }
    })
</script>

image-20220909123330319

method实现

<div id="app">
    姓:<input type="text" v-model="firstName"><br/>
    名:<input type="text" v-model="lastName"><br/>
    全名:<span>{{fullName()}}</span>
</div>
<script>
    new Vue({
        el: "#app",
        data() {
            return {
                firstName: "张",
                lastName: "三"
            }
        },
        methods: {
            fullName() {
                return this.firstName + '-' + this.lastName;
            }
        }
    })
</script>

image-20220909123527783

computed计算属性

  • 定义:要用的属性不存在,需要通过已有属性计算得来
  • 原理:底层借助了Objcet.defineproperty()方法提供的gettersetter
  • get函数什么时候执行?
    • 初次读取时会执行一次
    • 当依赖的数据发生改变时会被再次调用
  • 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
  • 备注
    • 计算属性最终会出现在vm上,直接读取使用即可
    • 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
    • 如果计算属性确定不考虑修改,可以使用计算属性的简写形式
<div id="app">
    姓:<input type="text" v-model="firstName"><br/>
    名:<input type="text" v-model="lastName"><br/>
    <!--这里修改不会调用fullName的get方法-->
    测试:<input type="text" v-model="x"><br/>
    全名:<span>{{fullName}}</span><br/>
    全名:<span>{{fullName}}</span><br/>
    全名:<span>{{fullName}}</span><br/>
    全名:<span>{{fullName}}</span>
</div>
<script>
    const vm = new Vue({
        el: "#app",
        data() {
            return {
                firstName: "张",
                lastName: "三",
                x: "你好"
            }
        },
        computed: {
            // 全写
            // fullName: {
            //     // get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
            //     // get什么时候被调用?1.初次读取fullName的时候。2,所依赖的数据发生变化的时候
            //     get() {
            //         console.log("get被调用了");
            //         // console.log(this === vm);   // true
            //         return this.firstName + '-' + this.lastName;
            //     },
            //     // set什么时候调用?当fullName被修改时。
            //     set(value) {
            //         console.log('set', value);
            //         const arr = value.split('-')
            //         this.firstName = arr[0];
            //         this.lastName = arr[1];
            //     }
            // }
            
            // 简写
            fullName() {
                console.log("get被调用了");
                return this.firstName + '-' + this.lastName;
            }
        },
    })
</script>

修改一次调用一次。

image-20220909125522500

2.1.2 监听属性
<div id="app">
    <h3>今天天气很{{info}}</h3>
    <button @click="changeWeather">切换天气</button>
</div>
<script>
    new Vue({
        el: "#app",
        data() {
            return {
                isHot: true,
            }
        },
        computed: {
            info() {
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot;
            }
        }
    })
</script>

image-20220909130759937

2.1.2.1 侦听属性基本用法

watch监视属性

  1. 当被监视的属性变化时,回调函数自动调用,进行相关操作
  2. 监视的属性必须存在,才能进行监视,既可以监视data,也可以监视计算属性
  3. 配置项属性immediate:false,改为 true,则初始化时调用一次handler(newValue,oldValue)
  4. 监视有两种写法
    1. 创建Vue时传入watch: {}配置
    2. 通过vm.$watch()监视
<div id="app">
    <h3>今天天气很{{info}}</h3>
    <button @click="changeWeather">切换天气</button>
</div>
<script>
    const vm = new Vue({
        el: "#app",
        data() {
            return {
                isHot: true,
            }
        },
        computed: {
            info() {
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot;
            }
        },
        // 监视的第一种写法
        watch: {
            isHot: {
                // handler什么时候调用?当isHot发生改变时。
                handler(newValue, oldValue) {
                    console.log("isHot被修改了");
                    console.log(newValue, oldValue);
                },
                // 初始化时让handler调用一下 默认为false
                immediate: true,
            },
            // info: {
            //     handler(newValue, oldValue) {
            //         console.log("info被修改了");
            //         console.log(newValue, oldValue);
            //     },
            // }
        }
    });

    // 监视的第二种写法
    // vm.$watch('isHot', {
    //     handler(newValue, oldValue) {
    //         console.log("isHot被修改了");
    //         console.log(newValue, oldValue);
    //     },
    //     immediate: true,
    // })
</script>

image-20220909132246899

2.1.2.2 深度侦听
  1. Vue中的watch默认不监测对象内部值的改变(一层)
  2. 在watch中配置deep:true可以监测对象内部值的改变(多层)

注意

  1. Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
  2. 使用watch时根据监视数据的具体结构,决定是否采用深度监视
<div id="app">
    <h3>a的值是:{{numbers.a}}</h3>
    <button @click="numbers.a++">点我让a+1</button>
    <h3>b的值是:{{numbers.b}}</h3>
    <button @click="numbers.b++">点我让b+1</button>
    <button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button>
    {{numbers.c.d.e}}
</div>
<script>
    const vm = new Vue({
        el: "#app",
        data() {
            return {
                numbers: {
                    a: 1,
                    b: 1,
                    c: {
                        d: {
                            e: 100,
                        }
                    }
                }
            }
        },
        watch: {
            // 监视多级结构中某个属性的变化
            'numbers.a': {
                handler(newValue, oldValue) {
                    console.log("a被改变了")
                }
            },
            // 监视多级结构中所有属性的变化
            numbers: {
                deep: true,
                handler(newValue, oldValue) {
                    console.log("numbers改变了");
                }
            }
        }
    });
</script>

image-20220909133624877

2.1.2.3 监听属性简写

如果监视属性除了handler没有其他配置项的话,可以进行简写

<div id="app">
    <h3>今天天气很{{info}}</h3>
    <button @click="changeWeather">切换天气</button>
</div>
<script>
    const vm = new Vue({
        el: "#app",
        data() {
            return {
                isHot: true,
            }
        },
        computed: {
            info() {
                return this.isHot ? '炎热' : '凉爽';
            }
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot;
            }
        },
        watch: {
            // 正常写法
            // isHot: {
            //     handler(newValue, oldValue) {
            //         console.log("isHot被修改了");
            //         console.log(newValue, oldValue);
            //     },
            //     immediate: true,
            //     deep: true, //深度监视
            // },

            // 简写
            isHot(newValue, oldValue) {
                console.log("isHot被修改了", newValue, oldValue, this)
            }
        }
    });

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

    // 简写
    // vm.$watch('isHot', (newValue, oldValue) => {
    //     console.log('isHot被修改了', newValue, oldValue, this);
    // })
</script>

image-20220909134111869

2.1.2.4 计算属性 VS 侦听属性

computed和watch之间的区别

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

两个重要的小原则

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

所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是

vm或组件实例对象

2.2 绑定样式与条件渲染

2.2.1 绑定样式

class样式

  • 写法::class="xxx",xxx可以是字符串、数组、对象
  • :style="[a,b]"其中a、b是样式对象
  • :style="{fontSize: xxx}"其中xxx是动态值

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

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

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>绑定样式</title>
    <script src="js/vue.js"></script>
    <style>
        .basic {
            width: 300px;
            height: 50px;
            border: 1px solid black;
        }

        .happy {
            border: 3px 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: skyblue;
        }

        .normal {
            background-color: #bfa;
        }

        .Teng1 {
            background-color: yellowgreen;
        }

        .Teng2 {
            font-size: 20px;
            text-shadow: 2px 2px 10px red;
        }

        .Teng3 {
            border-radius: 20px;
        }
    </style>
</head>
<body>
<div id="app">
    <!--绑定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>
<script>
    new Vue({
        el: '#app',
        data: {
            name: "Teng",
            mood: 'normal',
            classArr: ['Teng1', 'Teng2', 'Teng3'],
            classObj: {
                teng1: false,
                teng2: false,
            },
            styleObj: {
                fontsize: '40px',
                color: 'red',
            },
            styleObj2: {
                backgroundColor: 'orange'
            },
            styleArr: [
                {
                    fontsize: '40px',
                    color: 'blue',
                },
                {
                    backgroundColor: 'gray'
                }
            ]
        },
        methods: {
            changeMood() {
                const arr = ['happy', 'sad', 'normal'];
                const index = Math.floor(Math.random() * 3);
                this.mood = arr[index];
            }
        }
    })
</script>

</body>
</html>
2.2.2 条件渲染

v-if

写法跟if else语法类似,v-if="表达式"v-else-if="表达式"v-else

适用于:切换频率较低的场景,因为不展示的DOM元素直接被移除

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

v-show

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

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

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

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

template标签不影响结构,页面html中不会有此标签,但只能配合v-if,不能配合v-show

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

    <!--使用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 v-show="n === 1">Angular</div>
    <div v-show="n === 2">React</div>
    <div v-show="n === 3">Vue</div>

    <div v-if="n === 1">Angular</div>
    <div v-else-if="n === 2">React</div>
    <div v-else-if="n === 3">Vue</div>
    <div v-else>哈哈</div>

    <!--v-if与template的配合使用-->
    <template v-if="n === 1">
        <h3>你好</h3>
    </template>
</div>
<script>
    Vue.config.productionTip = false;
    new Vue({
        el: "#app",
        data: {
            name: "Teng",
            n: 0
        }
    });
</script>

2.3 列表渲染与数据监视

2.3.1 列表渲染
2.3.1.1 基本列表

v-for指令

用于展示列表数据

语法:<li v-for="(item, index) of items" :key="index">,这里key可以是index,更好的是遍历对象的唯一标识

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

<div id="app">
    <!--遍历数组-->
    <h3>人员列表</h3>
    <ul>
        <li v-for="(item, index) of persons" :key="index">{{item.name}}--{{item.age}}</li>
    </ul>

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

    <!--遍历字符串-->
    <h3>测试遍历字符串</h3>
    <ul>
        <li v-for="(item,index) of str" :key="index">{{item}}--{{index}}</li>
    </ul>
</div>
<script>
    Vue.config.productionTip = false;
    new Vue({
        el: "#app",
        data: {
            persons: [
                {id: '001', name: '张三', age: 18},
                {id: '002', name: '李四', age: 19},
                {id: '003', name: '王五', age: 20},
            ],
            car: {
                name: '玛莎拉蒂',
                price: '100w',
                color: '白色'
            },
            str: 'Hello'
        }
    })
</script>

image-20220909214840873

2.3.1.2 key的作用与原理

开发中如何选择key?

  • 最好使用每条数据的唯一标识作为key,比如 id、手机号、身份证号、学号等唯一值
  • 如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用index作为key是没有问题的
2.3.1.3 列表过滤
<div id="app">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keyWord">
    <ul>
        <li v-for="(item,index) of filPersons" :key="index">{{item.name}}--{{item.age}}--{{item.sex}}</li>
    </ul>
</div>
<script>
    Vue.config.productionTip = false;
    // 用watch实现
    // new Vue({
    //     el: "#app",
    //     data: {
    //         keyWord: '',
    //         persons: [
    //             {id: '001', name: '马冬梅', age: 18, sex: '女'},
    //             {id: '002', name: '周冬雨', age: 19, sex: '女'},
    //             {id: '003', name: '周杰伦', age: 20, sex: '男'},
    //             {id: '004', name: '温兆伦', age: 21, sex: '男'},
    //         ],
    //         filPersons: []
    //     },
    //     watch: {
    //         keyWord: {
    //             immediate: true,
    //             handler(newValue) {
    //                 this.filPersons = this.persons.filter((p) => {
    //                     return p.name.indexOf(newValue) !== -1;
    //                 })
    //             }
    //         }
    //     }
    // })

    // 用computed实现
    new Vue({
        el: "#app",
        data: {
            keyWord: '',
            persons: [
                {id: '001', name: '马冬梅', age: 18, sex: '女'},
                {id: '002', name: '周冬雨', age: 19, sex: '女'},
                {id: '003', name: '周杰伦', age: 20, sex: '男'},
                {id: '004', name: '温兆伦', age: 21, sex: '男'},
            ],
        },
        computed: {
            filPersons() {
                return this.persons.filter((p) => {
                    return p.name.indexOf(this.keyWord) !== -1;
                })
            }
        }
    })
</script>
2.3.1.4 列表排序
<div id="app">
    <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="(item,index) of filPersons" :key="item.id">{{item.name}}--{{item.age}}--{{item.sex}}</li>
    </ul>
</div>
<script>
    Vue.config.productionTip = false;

    new Vue({
        el: "#app",
        data: {
            keyWord: '',
            sortType: 0, // 0原顺序 1:降序 2:升序
            persons: [
                {id: '001', name: '马冬梅', age: 18, sex: '女'},
                {id: '002', name: '周冬雨', age: 28, sex: '女'},
                {id: '003', name: '周杰伦', age: 30, sex: '男'},
                {id: '004', name: '温兆伦', age: 31, sex: '男'},
            ],
        },
        computed: {
            filPersons() {
                const arr = this.persons.filter((p) => {
                    return p.name.indexOf(this.keyWord) !== -1;
                });
                // 判断是否需要进行排序
                if (this.sortType) {
                    arr.sort((p1, p2) => {
                        return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age;
                    })
                }
                return arr;
            }
        }
    })
</script>
2.3.2 数据监视

模拟一个小问题

<div id="app">
    <button @click="updateMei">更新马冬梅信息</button>
    <ul>
        <li v-for="(item,index) of persons" :key="item.id">
            {{item.name}}--{{item.age}}--{{item.sex}}
        </li>
    </ul>
</div>
<script>
    new Vue({
        el: "#app",
        data: {
            persons: [
                {id: '001', name: '马冬梅', age: 18, sex: '女'},
                {id: '002', name: '周冬雨', age: 28, sex: '女'},
                {id: '003', name: '周杰伦', age: 30, sex: '男'},
                {id: '004', name: '温兆伦', age: 31, 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. vue会监视data中所有层次的数据

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

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

    对象创建后追加的属性,Vue默认不做响应式处理

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

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

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

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

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

    • 调用原生对应的方法对数组进行更新
    • 重新解析模板,进而更新页面
  4. 在Vue修改数组中的某个元素一定要用如下方法
    push() pop() unshift() shift() splice() sort() reverse()这几个方法被Vue重写了Vue.set()或vm.$set()

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

<div id="app">
    <h1>学生信息</h1>
    <button @click="student.age++">年龄+1岁</button>
    <br/>
    <button @click="addSex">添加性别属性,默认值:男</button>
    <br/>
    <button @click="student.sex = '未知'">修改性别</button>
    <br/>
    <button @click="addFriend">在列表中添加一个朋友</button>
    <br/>
    <button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button>
    <br/>
    <button @click="addHobby">添加一个爱好</button>
    <br/>
    <button @click="updateHobby">修改第一个爱好为:开车</button>
    <br/>
    <button @clickr="removeSmoke">过滤掉爱好中的抽烟</button>
    <br/>
    <h3>姓名:{{student.name}}</h3><br/>
    <h3>年龄:{{student.age}}</h3>
    <h3 v-if="student.sex">性别:{{student.sex}}</h3>
    <h3>爱好:</h3>
    <ul>
        <li v-for="(item,index) in student.hobby" :key="index">{{item}}</li>
    </ul>
    <h3>朋友们:</h3>
    <ul>
        <li v-for="(item, index) in student.friends" :key="index">{{item.name}}--{{item.age}}</li>
    </ul>
</div>
<script>
    const vm = new Vue({
        el: "#app",
        data: {
            student: {
                name: 'tom',
                age: 18,
                hobby: ['抽烟', '喝酒', '烫头'],
                friends: [
                    {name: 'jerry', age: 35},
                    {name: 'tony', age: 36}
                ]
            }
        },
        methods: {
            addSex() {
                //Vue.set(this.student, 'sex', '男')
                this.$set(this.student, 'sex', '男');
            },
            addFriend() {
                this.student.friends.unshift({name: 'jack', age: 70});
            },
            updateFirstFriendName() {
                this.student.friends[0].name = '张三';
            },
            addHobby() {
                this.student.hobby.push('学习');
            },
            updateHobby() {
                this.$set(this.student.hobby, 0, '开车');
            },
            removeSmoke() {
                this.student.hobby = this.student.hobby.filter((h)=>{
                    return h !== '抽烟';
                })
            }
        }
    })
</script>

2.4 收集表单数据与过滤器

2.4.1 收集表单数据

收集表单数据

  • <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 输入首尾空格过滤
<div id="app">
    <form @submit.prevent="demo">
        账号:<input type="text" v-model.trim="userInfo.account"><br/>
        密码:<input type="password" v-model="userInfo.password"><br/>
        年龄:<input type="number" v-model.number="userInfo.age"><br/>
        性别:
        男:<input type="radio" name="sex" v-model="userInfo.sex" value="male">
        女:<input type="radio" name="sex" v-model="userInfo.sex" value="female"><br/>
        爱好:
        学习<input type="checkbox" v-model="userInfo.hobby" value="study">
        打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
        吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
        <br/>
        所属校区
        <select v-model="userInfo.city">
            <option value="">请选择校区</option>
            <option value="beijing">北京</option>
            <option value="henan">河南</option>
            <option value="shanghai">上海</option>
            <option value="shenzhen">深圳</option>
        </select>
        <br/>
        其他信息:
        <textarea v-model.lazy="userInfo.other"></textarea><br/>
        <input type="checkbox" v-model="userInfo.agree">阅读并接受
        <a href="https://github.com/CodeTeng">《用户协议》</a>
        <button>提交</button>
    </form>
</div>
<script>
    Vue.config.productionTip = false;

    new Vue({
        el: "#app",
        data: {
            userInfo: {
                account: '',
                password: '',
                age: '',
                sex: 'female',
                hobby: [],
                city: '',
                other: '',
                agree: ''
            }
        },
        methods: {
            demo() {
                console.log(JSON.stringify(this.userInfo));
            }
        }
    })
</script>

image-20220910110358489

2.4.2 过滤器(Vue3已经移除)

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

注册过滤器:

  • Vue.filter(name, callback) 全局过滤器
  • new Vue {filters: {}} 局部过滤器

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

备注:

  • 过滤器可以接收额外参数,多个过滤器也可以串联
  • 并没有改变原本的数据,而是产生新的对应的数据
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>过滤器</title>
    <script src="js/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js"></script>
</head>
<body>
<div id="app">
    <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>
<script>
    Vue.config.productionTip = false;
    // 全局过滤器
    Vue.filter('mySlice', (value) => {
        return value.slice(0, 11);
    })
    new Vue({
        el: "#app",
        data: {
            time: 1662781402,
        },
        // 局部过滤器
        filters: {
            timeFormater(value, str = "YYYY年MM月DD日 HH:mm:ss") {
                return dayjs(value).format(str)
            }
        }
    })
</script>
</body>
</html>

image-20220910114507487

2.5 内置指令与自定义指令

2.5.1 内置指令

之前学过的指令:

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

v-model 双向数据绑定

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

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

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

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

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

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

2.5.1.1 v-text指令

v-text指令

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

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

<div id="app">
    <div>你好,{{name}}</div>
    <div v-text="name">你好,</div>
    <div v-text="str"></div>
</div>
<script>
    new Vue({
        el: "#app",
        data: {
            name: "Teng",
            str: '<h3>你好!</h3>'
        }
    })
</script>

image-20220910115606101

2.5.1.2 v-html指令

v-html指令

作用:向指定节点中渲染包含html结构的内容

与插值语法的区别:

  • v-html会替换掉节点中所有的内容,{{xxx}}则不会
  • v-html可以识别html结构

严重注意v-html有安全性问题!!!

  • 在网站上动态渲染任意html是非常危险的,容易导致XSS攻击

  • 一定要在可信的内容上使用v-html,永远不要用在用户提交的内容上!!!

<div id="app">
    <div>你好,{{name}}</div>
    <div v-html="str"></div>
    <div v-html="str2"></div>
</div>
<script>
    new Vue({
        el: "#app",
        data: {
            name: "Teng",
            str: "<h3>你好!</h3>",
            str2: '<a href="https://github.com/CodeTeng/">兄弟我找到你想要的资源了!</a>'
        }
    })
</script>

image-20220910120233900

2.5.1.3 v-cloak指令

v-cloak指令(没有值)

  • 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性

  • 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>v-cloak</title>
    <script src="../js/vue.js"></script>
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>
<body>
<div id="app">
    <h2 v-cloak>{{name}}</h2>
</div>
<!--延迟5s收到vue.js-->
<!--<script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>-->
<script>
    new Vue({
        el: "#app",
        data: {
            name: "Teng"
        }
    })
</script>
</body>
</html>
2.5.1.4 v-once指令

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

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

<div id="app">
    <h2 v-once>初始化的n的值是:{{n}}</h2>
    <h2>当前的n的值是:{{n}}</h2>
    <button @click="n++">点我n+1</button>
</div>
<script>
    Vue.config.productionTip = false;
    new Vue({
        el: "#app",
        data: {
            n: 1,
        }
    })
</script>

image-20220910122836201

2.5.1.5 v-pre指令

跳过v-pre所在节点的编译过程

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

<div id="app">
    <h2 v-pre>Vue其实很简单</h2>
    <h2>当前的n值是:{{n}}</h2>
    <button @click="n++">点我n+1</button>
</div>
<script>
    new Vue({
        el: "#app",
        data: {
            n: 1,
        }
    })
</script>
2.5.2 自定义指令

directives

定义语法

  1. 局部指令
new Vue({
    directives: {
        指令名:配置对象
    }
})

new Vue({
    directives: {
        指令名:回调函数
    }
})
  1. 回调函数
Vue.directive(指令名, 配置对象)
或
Vue.directive(指令名, 回调函数)

Vue.directives('fbind', {
    // 指令与元素成功绑定时(一上来)
    bind(element, binding) { // element就是DOM元素,binding就是要绑定的
        element.value = binding.value;
    },
    // 指令所在元素被插入页面时
    inserted(element, binding) {
        element.focus();
    },
    // 指令所在的模板被重新解析时
    update(element, binding) {
        element.value = binding.value;
    }
})

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

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

element就是DOM元素,binding就是要绑定的对象,它包含以下属性:name value oldValue expression arg modifiers

备注

  • 指令定义时不加v-,但使用时要加v-
  • 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名
<div id="app">
    请输入内容:<input v-focus type="text">
</div>
<script>
    new Vue({
        el: "#app",
        data: {
            n: 1,
        },
        directives: {
            focus: {
                inserted(element) {
                    element.focus();
                }
            }
        }
    })
</script>

会被自动的聚焦到输入框

2.6 Vue声明周期

2.6.1 引出声明周期

生命周期

  • 又名生命周期回调函数、生命周期函数、生命周期钩子
  • 是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
  • 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
  • 生命周期函数中的this指向是vm或组件实例对象
<div id="app">
    <h2 :style="{opacity}">欢迎学习Vue</h2>
</div>
<script>
    new Vue({
        el: "#app",
        data: {
            opacity: 1
        },
        methods: {},
        // 挂载 Vue完成模板的解析并把初始的真实DOM元素放入页面后调用mounted()
        mounted() {
            console.log(this);
            setInterval(() => {
                this.opacity -= 0.01;
                if (this.opacity <= 0) this.opacity = 1
            }, 16);
        }
    });

    // 同步外部的定时器实现(不推荐)
    /*setInterval(() => {
        vm.opacity -= 0.01;
        if (vm.opacity <= 0) vm.opacity = 1
    }, 16);*/
</script>

效果.gif

2.6.2 分析声明周期

生命周期.png

<div id="app">
    <h2 v-text="n"></h2>
    <h2>当前的n值是:{{n}}</h2>
    <button @click="add">点我n+1</button>
    <button @click="bye">点我销毁vm</button>
</div>
<script>
    new Vue({
        el: "#app",
        // template: '<div><h2>当前的n值是:{{n}}</h2><button @click="add">点我n+1</button></div>',
        data: {
            n: 1,
        },
        methods: {
            add() {
                console.log("add");
                this.n++;
            },
            bye() {
                this.$destroy();
                console.log("bye");
            }
        },
        watch: {
            n() {
                console.log("n变了");
            }
        },
        beforeCreate() {
            console.log("beforeCreate");
            // console.log(this);
            // debugger;
        },
        created() {
            console.log("created");
            // console.log(this);
            // debugger;
        },
        beforeMount() {
            console.log("beforeMount");
            // console.log(this);
            // document.querySelector("h2").innerText = "123";
            // debugger;
        },
        mounted() {
            console.log("mounted");
            // console.log(this);
            // debugger;
        },
        beforeUpdate() {
            console.log("beforeUpdate");
            // console.log(this.n);
            // debugger;
        },
        updated() {
            console.log("updated");
            // console.log(this.n);
            // debugger;
        },
        beforeDestroy() {
            console.log("beforeDestroy");
            // console.log(this.n);
            // this.n = 99;   //不生效
        },
        destroyed() {
            console.log("destroyed");
        }
    })
</script>
2.6.3 总结声明周期

常用的生命周期钩子

  • mounted 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作
  • beforeDestroy 清除定时器、解绑自定义事件、取消订阅消息等收尾工作

关于销毁Vue实例

  • 销毁后借助Vue开发者工具看不到任何信息
  • 销毁后自定义事件会失效,但原生DOM事件依然有效
  • 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了
<div id="app">
    <h2 :style="{opacity}">欢迎学习Vue</h2>
    <button @click="opacity = 1">透明度设置为1</button>
    <button @click="stop">点我彻底停止变换</button>
</div>
<script>
    new Vue({
        el: "#app",
        data: {
            opacity: 1
        },
        methods: {
            stop() {
                this.$destroy();
            }
        },
        mounted() {
            console.log(this);
            this.timer = setInterval(() => {
                this.opacity -= 0.01;
                if (this.opacity <= 0) this.opacity = 1
            }, 16);
        },
        beforeDestroy() {
            clearInterval(this.timer);
            console.log("vm即将死亡");
        }
    });
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ambition0823

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

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

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

打赏作者

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

抵扣说明:

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

余额充值