Vue的进阶语法

223 阅读5分钟

自定义指令

  • 指令用于简化DOM操作,想当于对基础DOM操作的一种封装。
  • 当我们希望使用一些内置指令不具有的DOM功能时,可以进行自定义指令设置。

自定义全局指令

  • 范围:全局
  • 指的是:可以被任意Vue实例或组件使用的指令。
<body>
    <div id="app">
        <input type="text" v-focus = "100 + 1">
    </div>
    <script>
        // 自定义全局指令
        Vue.directive('focus',{
            // 钩子函数
            inserted(el,binding){
                console.log(el);
                console.log(binding);
                // 获得焦点事件
                el.focus();
            }
        });
        new Vue({
            el: "#app",
            data:{

            },methods:{

            }
        });
    </script>
</body>
  • 当全局指令focus,绑定两个Input,运行页面后,会显示在第二个input中,因为在页面中只能聚焦一个。

钩子函数参数

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。

自定义局部指令

  • 范围:局部
  • 指的是:可以在当前Vue实例或组件内使用的指令。
<body>
    <div id="app">
        <input type="text" v-focus = "100 + 1">
    </div>
    <div id="app2">
        <!-- 无法使用局部的指令,报错 -->
        <input type="text" v-focus>
    </div>
    <script>
        new Vue({
            el: "#app",
            data:{

            },methods:{

            },
            // 定义局部指令
            directives: {
                // 指令的名称
                focus: {
                    inserted(el){
                        el.focus();
                    }
                }
            }
        });
        new Vue({
            el: '#app2',
            data: {

            },methods: {
                
            }
        });
    </script>
</body>

过滤器

  • 过滤器用于进行文本内容格式化处理。
  • 过滤器可以在插值表达式v-bind中使用。
  • 视图中显示的数据,来自于过滤器的返回值。
  • 需要使用管道符:|

全局过滤器

  • 初级:将一个数据传入一个过滤器中进行处理(页面呈现:abc)
<body>
    <div id="app">
        <!-- 插值表达式 | :管道符-->
        <p>{{value | filterA}}</p>
        <!-- v-bind -->
        <p v-bind:title="value | filterA">这是标签</p>
    </div>
    <script src="lib/vue.js"></script>
    <script>
        // 自定义全局过滤器
        Vue.filter('filterA',function(value){
            // 过滤器只是输出语句,并没有返回任何信息,那么视图层也不会显示任何信息
            console.log(value);
            return value.split('-').join('');
        });
        new Vue({
            el:'#app',
            data: {
                value:'a-b-c'
            },methods: {
                
            }
        });
    </script>
</body>
  • 可以将一个数据传入到多个过滤器中进行处理。(页面呈现:Abc)
<body>
    <div id="app">
        <!-- 插值表达式 | :管道符-->
        <p>{{value | filterA | filterB}}</p>
    </div>
    <script src="lib/vue.js"></script>
    <script>
        // 自定义全局过滤器
        Vue.filter('filterA',function(value){
            // 过滤器只是输出语句,并没有返回任何信息,那么视图层也不会显示任何信息
            console.log(value);
            // 将字符串分割成数组,再拼接起来
            return value.split('-').join('');
        });
        Vue.filter('filterB',function(value){
            // slice:字符串截取
            return value[0].toUpperCase() + value.slice(1);
        });
        new Vue({
            el:'#app',
            data: {
                value:'a-b-c'
            },methods: {
                
            }
        });
    </script>
</body>
  • 一个过滤器可以传入多个参数。
<body>
    <div id="app">
        <!-- 给一个过滤器传入多个参数 -->
        <p>{{value | filterA | filterC('baidu-',200)}}</p>
    </div>
    <script src="lib/vue.js"></script>
    <script>
        // 自定义全局过滤器
        Vue.filter('filterA',function(value){
            // 过滤器只是输出语句,并没有返回任何信息,那么视图层也不会显示任何信息
            console.log(value);
            return value.split('-').join('');
        });
        // 一个过滤器可以传入多个参数: 参数1是数据层绑定的数据
        Vue.filter('filterC',function(para1,para2,para3){
            return para2 + para1;
        });
        new Vue({
            el:'#app',
            data: {
                value:'a-b-c'
            },methods: {
                
            }
        });
    </script>
</body>

局部过滤器

  • 局部过滤器只能在当前Vue实例中使用。(案例:局部过滤器的作用范围)
<body>
    <div id="app">
        <P>{{content | filterA}}</P>
    </div>
    <div id="app2">
        <!-- 报错 vue.js:634 [Vue warn]: Failed to resolve filter: filterA-->
        <p>{{content | filterA}}</p>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                content: 'a-b-f'
            },methods: {

            },
            // 定义局部过滤器
            filters: {
                filterA: function(value){
                    return value.split('-').join('');
                }
            }
        });

        new Vue({
            el: '#app2',
            data: {
                content: 'g-t-s'
            }
        });
    </script>
</body>
  • 将一个数据传入多个过滤器中进行处理(页面呈现:fba)
<body>
    <div id="app">
        <P>{{content | filterA | filterB}}</P>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                content: 'a-b-f'
            },methods: {

            },
            // 定义局部过滤器
            filters: {
                filterA: function(value){
                    return value.split('-');
                },
                // 过滤器的函数简写方式
                filterB(value){
                    return value.reverse().join('');
                }
            }
        });
    </script>
</body>
  • 将多个数据传入一个过滤器中进行处理(页面呈现:baidu-fba)
<body>
    <div id="app">
        <P>{{content | filterA | filterB('baidu-')}}</P>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                content: 'a-b-f'
            },methods: {

            },
            // 定义局部过滤器
            filters: {
                filterA: function(value){
                    return value.split('-');
                },
                filterB(value,prefix){
                    return prefix + value.reverse().join('');
                }
            }
        });
    </script>
</body>
  • 当全局过滤器和局部过滤器重名,会执行局部过滤器(页面呈现:baidu-fba)
<body>
    <div id="app">
        <P>{{content | filterA | filterB('baidu-')}}</P>
    </div>
    <script>
        // 同名的全局过滤器
        Vue.filter('filterA',function(value){
            return 'Hello,filterA'.split('');
        });
        new Vue({
            el: '#app',
            data: {
                content: 'a-b-f'
            },methods: {

            },
            // 定义局部过滤器
            filters: {
                filterA: function(value){
                    // 将字符串拆分成数组
                    return value.split('-');
                },
                filterB(value,prefix){
                    // 数组方法
                    return prefix + value.reverse().join('');
                }
            }
        });
    </script>
</body>

问题

  • 当既有全局过滤器又有局部过滤器的时候,两个重名会怎么样?
    • 只有局部过滤器会生效。
  • 总结:可以在去全局中定义一些基本的全局过滤器,在某一个实例的功能中,希望去进行新的功能设置,就可以通过重名的方式去层叠掉全局的过滤器。以此达到不同的Vue实例中,同名过滤器的功能不太一样。

计算属性

  • 通过减少函数执行次数的操作,提高执行效率

methods与computed区别

  • computed具有缓存型,methods没有。
  • computed通过属性名访问,methods需要调用
  • computed仅适用于计算操作。

计算属性的适用场景(练习)

  • 计算属性可以将计算的结果进行缓存,当我们后续进行使用时,只要数据没有发生改变,那么计算是不会重复执行的,而是直接读取缓存中的数据。
  • v-for比v-if优先级高,效率低(不推荐)
  • methods适用于数据只使用一次
  • 计算数据处理数据使用一次或多次,效率都高(推荐)
  • 演示代码
<body>
    <div id="app">
        <!-- 不推荐 -->
        <!-- <p v-if="item > 10" v-for="item in arr">{{item}}</p> -->
        <p v-for="item in result">{{item}}</p>
    </div>
    <script src="../note/lib/vue.js"></script>
    <script>
        var vm = new Vue({
            el:'#app',
            data:{
                arr:[2,67,45,9,0]
            },
            methods:{
                // 通过方法处理函数,返回处理好的数组
                result(){
                    var resultArr = [];
                    for(var i = 0;i < this.arr.length; i++){
                        if(this.arr[i] > 10){
                            resultArr.push(this.arr[i]);
                        }
                    }
                    return resultArr;
                }
            }
            computed:{
                //只会执行一次,通过属性名调用
                result(){
                    var resultArr = [];
                    for(var i = 0;i < this.arr.length; i++){
                        if(this.arr[i] > 10){
                            resultArr.push(this.arr[i]);
                        }
                    }
                    return resultArr;
                }
            }
        });
    </script>
</body>

计算属性的setter(修改计算属性执行的操作)

  • 计算属性默认只有getter,Vue.js也允许给计算属性设置setter.
  • 演示代码(// 控制台中:vm.fullName = "王 小美")
<body>
    <div id="app">
        <p>{{fullName}}</p>
    </div>
    <script src="../note/lib/vue.js"></script>
    <script>
        var vm = new Vue({
            el:'#app',
            data:{
                firstName:'张',
                lastName:'里斯'
            },
            computed: {
                // 默认书写方式
                // fullName(){
                //     return this.firstName + this.lastName;
                // }
                // 分开书写getter 与 setter
                // 控制台中:vm.fullName = "王 小美"
                fullName: {
                    get(){
                        return this.firstName + this.lastName;
                    },set(newName){
                        var nameArr = newName.split(' ');
                        this.firstName = nameArr[0];
                        this.lastName = nameArr[1];
                    }
                }
            }
        });
    </script>
</body>

侦听器

  • 用于监听数据变化并执行指定操作。
  • 演示代码(最基础的侦听)
<body>
    <div id="app">
        <input v-model='value'>
    </div>
    <script src="../note/lib/vue.js"></script>
    <script>
        var vm = new Vue({
            el:'#app',
            data:{
                value:''
            },
            // 侦听数据
            watch:{
                value(val,oldval){
                    // 输出新的值 和 旧的值
                    console.log('value被修改了',val,oldval);
                }
            }
        });
    </script>
</body>
  • 为了监听内部值的变化,需要将watch书写为对象,并设置选项deep:true,这时通过handler设置处理函数。

监听对象本身和对象内部数据的变化(deep:true)

  • 演示代码
<script src="../note/lib/vue.js"></script>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
            obj:{
                content1:'内容1',
                content2:'内容2'
            }
        },
        // 侦听数据
        watch:{
            // obj(){
            //     // 可以实现整体obj的赋值变化,但是内部改变不会触发侦听函数
            //     console.log('obj被修改了');
            // }
            obj:{
                deep:'true',
                handler(){
                    console.log('obj被修改了');
                }
            }
        }
    });
</script>

注意

  • 数组不需要像对象那样,不添加deep:true;
  • 当更改(非替换)数组或对象时,回调函数中的新值与旧值相同,因为它们的引用都指向同一个数组、对象。
  • 数组操作不要使用索引与length,无法触发侦听器函数。(可使用Push\pop\Vue.set())
  • 演示代码
<script src="../note/lib/vue.js"></script>
<script>
    var vm = new Vue({
        el:'#app',
        data:{
            value:'',
            obj:{
                content1:'内容1',
                content2:'内容2'
            },
            arr:[3,56,23,99]
        },
        // 侦听数据
        watch:{
            arr(val,oldval){
                //成功执行了侦听函数,发现新值和旧值相同
                console.log('arr被修改了',val,oldval);
            }
        }
    });
</script>

Vue DevTools

  • 是Vue.js官方提供的用来调试Vue应用的工具。
  • 注:谷歌访问助手下载地址:chrome.zzzmh.cn/

注意事项(3点满足才可以看到在控制台看到Vue)

  • 1.网页必须应用了Vue.js功能
  • 2.网页必须使用Vue.js而不是Vue.min.js
  • 3.网页需要在http协议下打开,而不是使用file协议本地打开
  • 注:只适用于含有vue功能的网页的调试

vue_devtools.png

Vue.js生命周期

  • Vue.js生命周期指的是Vue实例的生命周期。
  • Vue实例的生命周期,指的是实例从创建到运行,再到销毁的过程。

Vue.js生命周期函数

  • 通过设置生命周期函数,可以在生命周期的特定阶段执行功能。
  • 生命周期函数也称为生命周期钩子。

创建阶段

  • beforeCreate:实例初始化之前调用
  • created:实例创建后调用
  • beforeMount:实例挂载之前调用
  • mounted:实例挂载完毕
  • 特点:每个实例只能执行一次

运行阶段

  • beforeUpdate:数据更新后,视图更新前调用
  • updated:视图更新后调用
  • 特点:按需调用

销毁阶段

  • beforeDestory:实例销毁之前调用
  • destoryed:实例销毁之后调用
  • 特点:每个实例只能执行一次