前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue.js基础特性

Vue.js基础特性

作者头像
河湾欢儿
发布2018-09-06 17:23:09
1.8K0
发布2018-09-06 17:23:09
举报

计算属性 computed 与data,el,methods属性一样,都是vm实例的属性(选项) 理解其大致意思即可

绑定表达式 一段绑定表达式可以由一个简单的js表达式和可选的一个或多个过滤器组成

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="../node_modules/vue/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">
            <!--字符串拼接-->
            <p>{{ message + "----" + name }}</p>
            <!--三元运算符-->
            <p>{{ bool ? 1 : 0 }}</p>
            <!--四则运算-->
            <p>{{ num * 2 }}</p>
        </div>
    </body>
</html>
<!--
    使用的限制是只能包含单个表达式
-->
<script>
    //创建Vue对象
    var app =new Vue ({
        el:'#app',//将Vue对象绑定到指定的选择器
        data:{
            message: 'hello world ',
            name:'莉莉',
            bool: true,
            num:10
        }
    })
</script>

上面已经讲解过绑定表达式的相关知识点,即在 {{}}内部支持js表达式

{{}} 内的表达式是非常便利的,但是它们实际上只用于简单的运算,并且只能够支持单个js表达式,多个就会报错。

在模板中放入太多的逻辑会让模板过重且难以维护。

<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

computed 针对这些复杂的逻辑,提出了计算属性这一要求 也就是说,将我们复杂的计算逻辑提取出来

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>

    <body>
        <div id="app">
            <!--在这里加入模型数据-->
            <h2>正常情况下的结果:{{ message }}</h2>
            <!--正常情况下,模板结构变得复杂,特别是在多次使用复杂逻辑的时候-->
            <h2>{{ message.split('').reverse().join('') }}</h2>
            <!--使用计算属性,使模板更简洁-->
            <h2>{{ reverseMessage }}</h2>
            <input type="text" v-model="message" />
        </div>
    </body>
</html>
<script>
    var dataModel = {
        message: 'hello world!'
    }
    var vm = new Vue({
        el: '#app',
        data: dataModel,
       //我们可以像绑定普通属性那样绑定计算属性:计算属性定义在computed内部,和data类似
        computed: {
            //在这里,我们将计算的逻辑提取出来,封装成一个函数,在函数的内部分使用return来定义返回值,返回计算的结构
            reverseMessage: function() {
                return this.message.split("").reverse().join("");
            }
        }
    })
</script>

要勤于复习哦! 你可能已经注意到我们可以通过调用表达式中的 method 来达到同样的效果: 在这里存在一些区别,涉及到缓存和性能的问题,下面我们将进行详细的讨论

methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

计算缓存 methods vs computed 1.使用methods: 每次使用都会执行一次函数,不存在像计算属性那样的缓存,会浪费性能 2.计算属性的优点: 不同的计算属性是会基于他们的依赖进行缓存的,只有在依赖关系发生变化时,才会重新求值 当依赖关系没有发生变化时,不会重新求值,会使用上一次计算缓存的结果

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>

    <body>
        <div id="app">
            <!--在这里加入模型数据-->
            <h2>正常情况下的结果:{{ message }}</h2>
            <h2>使用计算属性得出的结果:{{ reverseMessageComputed }}</h2>             
            <h2>使用methods方法得出的结果:{{ reverseMessageMethods() }}</h2>
            <input type="text" v-model="message" />
        </div>
    </body>

</html>
<script>
    var dataModel = {
        message: 'hello world!'
    }
    var vm = new Vue({
        el: '#app',
        data: dataModel,
        //计算属性的优点: 不同的计算属性是会基于他们的依赖进行缓存的,只有在依赖关系发生变化时,才会重新求值
        //当依赖关系没有发生变化时,不会重新求值,会使用上一次计算缓存的结果
        computed: {
            reverseMessageComputed: function() {
                return this.message.split("").reverse().join("");
            }
        },
        //使用methods: 每次使用都会执行一次函数,不存在像计算属性那样的缓存,会浪费性能
        methods: {
            reverseMessageMethods: function() {
                return this.message.split("").reverse().join("");
            }
        }
    })
</script>

computed vs methods的缓存效果演示 通过这个演示,你需要知道,对于一些单只需要纯的计算获取结果的内容,使用计算属性,能够提高性能,尤其是一些性能耗费比较严重的问题 一次增加绑定的数据的个数,根据渲染的时间来判定不同的效果 computed: 在增加绑定数据的个数的时候,渲染的时间基本不会变化(依赖关系没有发生变化) methods: 在增加绑定数据的个数的时候,渲染的时间会随着渲染的次数的增加而递增(依赖关系没有发生变化)

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>

    <body>
        <div id="app">
        </div>
    </body>

</html>
<script>
    var startTime = Date.now()
    var str =
        '{{ reverseMessageMethods()  }}{{ reverseMessageMethods()  }}' +
        '{{ reverseMessageMethods()  }}{{ reverseMessageMethods()  }}' +
        '{{ reverseMessageMethods()  }}{{ reverseMessageMethods()  }}' +
        '{{ reverseMessageMethods()  }}{{ reverseMessageMethods()  }}' +
        '{{ reverseMessageMethods()  }}{{ reverseMessageMethods()  }}';
    document.getElementById("app").innerHTML = str;
    var dataModel = {
        message: 'hello world!'
    }
    var vm = new Vue({
        el: '#app',
        data: dataModel,
        //使用methods: 每次使用都会执行一次函数,不存在像计算属性那样的缓存,会浪费性能
        methods: {
            reverseMessageMethods: function() {
                function fn(n) {
                    if(n === 1) {
                        return 1;
                    }
                    if(n === 2) {
                        return 1;
                    } else {
                        return fn(n - 1) + fn(n - 2);
                    }
                }
                var num = fn(35)
                return num;
            }
        }
    })

    //-----------------计算属性-----缓存演示


    var endTime = Date.now()
    console.log(endTime - startTime)
    var startTime = Date.now()
    var str1 =
        '{{ reverseMessageComputed  }}{{ reverseMessageComputed  }}' +
        '{{ reverseMessageComputed  }}{{ reverseMessageComputed  }}' +
        '{{ reverseMessageComputed  }}{{ reverseMessageComputed  }}' +
        '{{ reverseMessageComputed  }}{{ reverseMessageComputed  }}' +
        '{{ reverseMessageComputed  }}{{ reverseMessageComputed  }}';
    document.getElementById("app").innerHTML = str1;
    var dataModel = {
        message: 'hello world!'
    }
    var vm1 = new Vue({
        el: '#app',
        data: dataModel,
        //计算属性的优点: 不同的计算属性是会基于他们的依赖进行缓存的,只有在依赖关系发生变化时,才会重新求值
        //当依赖关系没有发生变化时,不会重新求值,会使用上一次计算缓存的结果
        computed: {
            reverseMessageComputed: function() {
                function fn(n) {
                    if(n === 1) {
                        return 1;
                    }
                    if(n === 2) {
                        return 1;
                    } else {
                        return fn(n - 1) + fn(n - 2);
                    }
                }
                var num = fn(35)
                return num;
            }
        }
    })
    var endTime = Date.now()
    console.log(endTime - startTime)
</script>

watch属性 vue提供的一种更通用的方式来观察和响应 Vue 实例上的数据变动的方式 当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch 通常更好的想法是使用 computed 属性而不是命令式的 watch 回调

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>

    <body>
        <div id="app">

            <h2>watch监视:{{ fullName }}</h2>
            <input type="text" v-model="firstName" /><br />
            <input type="text" v-model="lastName" /><br />

        </div>
    </body>

</html>
<script>
    var dataModel = {
        firstName: "firstName",
        lastName: "lastName",
        fullName: "firstName  lastName"
    }
    var vm = new Vue({
        el: '#app',
        data: dataModel,
        watch: {
            //在变量变化的时候,会自动执行这个函数    参数val就是绑定的值
            firstName: function(val) {
                this.fullName = val + ' ' + this.lastName
            },
            //在这里:val获取的是执行该函数的元素的内容  参数val就是绑定的值
            lastName: function(val) {
                this.fullName = this.firstName + ' ' + val
            }
        }
    })
</script>

getter 和 setter属性 (了解) 计算属性默认只有getter ,我们可以在需要的时候提供一个setter 也就是进行数据的读取和设置的操作 定义get和set方法,需要的时候直接调用

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>

    <body>
        <div id="app">

        </div>
    </body>

</html>
<script>
    var dataModel = {
        a: 1
    }
    var vm = new Vue({
        el: '#app',
        data: dataModel,
        computed: {
            //默认情况下,只会进行值的读取
            aDouble: function() {
                return this.a * 2
            },
            //在需要的时候进行值的读取和设置
            aPlus: {
                get: function() {
                    return this.a + 1;
                },
                set: function(v) {
                    this.a = v - 1;
                }
            }

        }

    })
    console.log(vm.aPlus) //2---------执行的是值的读取,也就是默认进行值的读取getter
    vm.aPlus = 100          //------------执行的是值的设置,也就是setter
    console.log(vm.a) //99
    //调用computed方法,在没有参数的时候,不需要添加参数,否则的话,会报错
    console.log(vm.aDouble) //4 --------------执行的是值的读取
</script>

观察者 watchers(了解) 当然啦,一项技术或者是理念的提出都是有其依据的 虽然我们提到watch是有弊端的,但是其存在还有其具体的意义 我们配合下面这个例子做作一个简单的介绍

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
        <script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js"></script>
        <script src="https://unpkg.com/lodash@4.13.1/lodash.min.js"></script>
    </head>

    <body>
        <div id="watch-example">
            <p>
                Ask a yes/no question:
                <input v-model="question">
            </p>
            <p>{{ answer }}</p>
        </div>
    </body>

</html>
<script>
    var watchExampleVM = new Vue({
        el: '#watch-example',
        data: {
            question: '',
            answer: 'I cannot give you an answer until you ask a question!'
        },
        watch: {
            // 如果 question 发生改变,这个函数就会运行
            question: function(newQuestion) {
                this.answer = 'Waiting for you to stop typing...'
                this.getAnswer()
            }
        },
        methods: {
            // _.debounce 是一个通过 lodash 限制操作频率的函数。
            // 在这个例子中,我们希望限制访问yesno.wtf/api的频率
            // ajax请求直到用户输入完毕才会发出
            // 学习更多关于 _.debounce function (and its cousin
            // _.throttle), 参考: https://lodash.com/docs#debounce
            getAnswer: _.debounce(
                function() {
                    var vm = this
                    if(this.question.indexOf('?') === -1) {
                        vm.answer = 'Questions usually contain a question mark. ;-)'
                        return
                    }
                    vm.answer = 'Thinking...'
                    axios.get('https://yesno.wtf/api')
                        .then(function(response) {
                            vm.answer = _.capitalize(response.data.answer)
                        })
                        .catch(function(error) {
                            vm.answer = 'Error! Could not reach the API. ' + error
                        })
                },
                // 这是我们为用户停止输入等待的毫秒数
                500
            )
        }
    })
</script>

在这个示例中,使用 watch 选项允许我们执行异步操作(访问一个 API), 限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这是计算属性无法做到的。

事件绑定与监听 之前我们已经讲解过v-on这个指令,可以监听dom,触发js代码,在这里我们先做一个简单的回顾

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>

    <body>
        <div id="app">
            <!--在这里加入模型数据-->
            {{ message }}

            <ul>
                <button v-on:click="clickNum = clickNum + 1">click me!</button>
                <li>这个按钮呗点击了 {{clickNum}} 次</li>
            </ul>

        </div>
    </body>

</html>
<script>
    var dataModel = {
        message: 'hello world!',
        clickNum: 0
    }
    var vm = new Vue({
        el: '#app',
        data: dataModel
    })
</script>

方法和事件处理器 通过v-on可以绑定方法,方法支持传参 有时候,我们需要访问原生的dom事件,需要使用特殊变量$event将它传入方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>
    <body>
        <div id="app">
            <!--在这里加入模型数据-->
            {{ message }}

            <!--不带参数-->
            <button v-on:click="sayHi1">不带参数</button>

            <!--带参数-->
            <button v-on:click="sayHi2('say what')">带参数</button>

            <!--使用原生dom事件,传递$event这个特殊参数-->
            <button v-on:click="sayHi3('say what',$event)">特殊参数</button>

        </div>
    </body>
</html>
<script>

    var dataModel = {
        message: 'hello world!'
    }
    var vm= new Vue({
        el:'#app',
        data:dataModel,
        methods:{
            sayHi1:function(){
                console.log("hello")
            },
            sayHi2:function(msg){
                console.log(msg)
            },
            sayHi3:function(msg,event){
                console.log(msg,event.target)
            }
        }
    })


    //通过js调用处理,和上面得到的结果是相同的
    //区别是: 点击执行(事件处理函数)与直接执行

    vm.sayHi1("test")
</script>

修饰符 之前我们提到过一些指令的修饰符,和这里的修饰符都是类似的东西,帮助我们解决一些实际的问题

事件修饰符 在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。 尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。 为了解决这个问题, Vue.js 为 v-on 提供了 事件修饰符。通过由点(.)表示的指令后缀来调用修饰符。

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>

    <body>
        <div id="app">
            <!--在这里加入模型数据-->
            {{ message }}

            <!-- 阻止单击事件冒泡 -->
            <a v-on:click.stop="doThis"></a>

            <!-- 提交事件不再重载页面 -->
            <form v-on:submit.prevent="onSubmit"></form>

            <!-- 修饰符可以串联  -->
            <a v-on:click.stop.prevent="doThat"></a>

            <!-- 只有修饰符 -->
            <form v-on:submit.prevent></form>

            <!-- 添加事件侦听器时使用事件捕获模式 -->
            <div v-on:click.capture="doThis">...</div>

            <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
            <div v-on:click.self="doThat">...</div>

            <!-- 点击事件将只会触发一次 -->
            <a v-on:click.once="doThis"></a>

        </div>
    </body>

</html>

<!--

.stop:  event.stopPropagation()
.prevent   event.preventDefault()
.capture  : 捕获
.self   : 只有当该元素是事件本身时触发回调
.once  : 只会触发一次



-->

<script>
    var dataModel = {
        message: 'hello world!'
    }
    var vm = new Vue({
        el: '#app',
        data: dataModel
    })
</script>

按键修饰符 同样的,在按键事件中也给我们提供了一些较为便利的操作(修饰符)

.enter
.tab
.delete (捕获 “删除” 和 “退格” 键)
.esc
.space
.up
.down
.left
.right   
 -------------------------------------------------支持链式写法

 2.1.0新增
 .ctrl
.alt
.shift
.meta:   对应的是window键

简单演示

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    </head>

    <body>
        <div id="app">
            <!--在这里加入模型数据-->
            {{ message }}

            <!-- 只有在keyCode的值是13时  调用vm.submit    13:回车键/enter键-->
            <input v-on:keyup.13="submit"></input>

            <!-- 同上   支持链式写法-->
            <input v-on:keyup.enter="submit">

            <!-- 缩写语法 -->
            <input @keyup.enter="submit">



        </div>
    </body>

</html>

<script>
    var dataModel = {
        message: 'hello world!'
    }
    var vm = new Vue({
        el: '#app',
        data: dataModel,
        methods: {
            submit: function() {
                console.log("submit")
            }
        }
    })
    /**
     * 
     *可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
     * 
     * 
     */

    Vue.config.keyCodes.f1 =112;
</script>

与传统事件绑定的区别 你可能注意到这种事件监听的方式违背了关注点分离(separation of concern)传统理念。 不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。 实际上,使用 v-on 有几个好处:

1. 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
2. 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
3. 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何自己清理它们。

new Vue()和Vue.extend() 之前我们讲解到,vue的两大特性: 数据的 双向绑定和组件化

在这里,我们对组件化进行更深一步的了解

new Vue() new Vue()创建的是vue的一个实例,之前我们提到过,vue是只关注视图层 我们可以将页面看成是一个大的根组件,里面包含的元素就是子组件,子组件可以在不同的根组件中被调用 那么,如何创建子组件呢,这个是我们需要关注的主题

Vue.extend() 在vue中给我们提供的创建组价的方式, 在这里,我们先了解一下这个方法,之后再做详细的讲解

两者的共性 构造器 每个 Vue.js 应用的起步都是通过构造函数 Vue 创建一个 Vue 的根实例(根组件) 可以扩展 Vue 构造器,从而用预定义选项创建可复用的组件构造器

TIM截图20180507164025.png

分析

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <!--引入js-->
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">

        </div>
    </body>
</html>
<!--

    vue这个对象可以进行扩展

    相当于在原先的vue的基础上添加新的内容,形成我们自己的,别具一格的vue


-->
<script>

    //1. 扩展vue对象
    var vueExtend = Vue.extend({
        //----定义扩展的vue的对象的内容
        template:'<div><a href="#">注册</a><a href="#">登录</a></div>'
    })

    //3. 创建根实例
    var vm = new vueExtend({
        el:'#app'
    })
</script>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.05.07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档