VUE常用知识点Vue.js

Vue.js第2课-基础

2019-05-11  本文已影响20人  e20a12f8855d

一、Vue.js 实例

一个 Vue.js 的项目,是由很多个组件组成的,Vue.js 组件也是一个实例,也可以说一个 Vue.js 的项目是由很多很多 Vue.js 实例拼装成的。

<div id="app">
    <div v-on:click="clickFun">{{msg}}</div>
    <test></test>
</div>
<script>
    // 创建一个全局组件
    Vue.component('test', {
        template: "<h1>hello</h1>"
    })

    var app = new Vue({
        el: "#app",
        data: {
            msg: "hello world"
        },
        methods: {
            clickFun() {
                alert("hello");
            }
        }
    })
    console.log(app); // wn {_uid: 0, _isVue: true, $options: {…}, _renderProxy: wn, _self: wn, …}
    console.log(app.$el); // <div id="app"><div>hello world</div></div>
    console.log(app.$data); // {__ob__: we}
    console.log(app.$data.msg); // hello world
</script>

二、Vue.js 实例生命周期函数

生命周期函数就是 Vue.js 实例在某一个时间点会自动执行的函数,这些函数并不是放到 methods 中,而是直接放到 Vue.js 的实例中。

<div id="app"></div>
<script>
    var app = new Vue({
        el: "#app",
        template: "<div>{{msg}}</div>",
        data: {
            msg: "hello world"
        },
        // Vue 实例部分初始化的时候执行
        beforeCreate: function () {
            console.log("beforeCreate");
        },
        created: function () {
            console.log("create");
        },
        beforeMount: function () {
            console.log(this.$el); // <div id="app"></div>
            console.log("beforeMount");
        },
        mounted: function () {
            console.log(this.$el); // <div>hello word</div>
            console.log("mounted");
        },
        // beforeDestroy 和 destroyed 需要先销毁,才会执行,在控制台执行 app.$destroy
        beforeDestroy: function () {
            console.log("beforeDestroy");
        },
        destroyed: function () {
            console.log("destroyed");
        },
        // 当数据发生改变时,beforeUpdate 和 updated 才会执行
        beforeUpdate: function () {
            console.log("beforeUpdate");
        },
        updated: function () {
            console.log("updated");
        }
    })
</script>

下图是 Vue.js 官网上生命周期图示:

三、Vue.js 的模板语法

1、插值表达式

<div id="app">{{msg}}</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            msg: "Hello World!"
        }
    })
</script>

2、v-text

v-text 指令,让标签内的 innerText 和 msg 绑定,后面的值是一个 js 表达式:

<div id="app">
    <div id="Vtext" v-text="msg"></div>
</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            msg: "Hello World!"
        }
    })
    var Vtext = document.getElementById('Vtext');
    console.log(Vtext.innerText); // Hello World!
</script>

3、v-html

v-html 让标签内的 innerHTML 和 msg 绑定:

<div id="app">
    <div id="Vhtml" v-html="msg"></div>
</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            msg: "Hello World!"
        }
    })
    var Vhtml = document.getElementById('Vhtml');
    console.log(Vhtml.innerHTML); // Hello World!
</script>

目前来看,v-text 和 v-html 没有区别,我们把 msg 中的值变成一个标签,例如放到 h1 标签中,v-text 渲染的依然是 “< h1>hello</ h1>”,而 v-html 渲染出的就是 h1 字号的 “hello”。

<div id="app">
    <div v-text="msg"></div>
    <div v-html="msg"></div>
    ---
    <div v-text="msg2"></div>
    <div v-html="msg2"></div>
</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            msg: "Hello World!",
            msg2: "<h1>Hello World!</h1>"
        }
    })
</script>

通过以上的例子得出,插值表达式和 v-text 的渲染结果是一样的。

凡是 “v-***” 后面的内容都是一个 js 表达式,在表达式中,不仅可以写一个变量,还可以往后面加一个字符串,插值表达式中也可以写 js 表达式:

<div id="app">
    {{msg + ' world1'}}
    <div v-text="msg + ' world!'"></div>
    <div v-html="msg + ' world!'"></div>
</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            msg: "Hello"
        }
    })
</script>

四、计算属性,方法和侦听器

fullName 的计算。

方式一:computed 计算属性(有缓存机制,会提高性能)

<div id="app">{{fullName}} {{age}}</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            firstName: "Liu",
            lastName: "Zhenghe",
            age: 26
        },
        computed: {
            fullName: function () {
                console.log("计算了一次!");
                return this.firstName + this.lastName;
            }
        }
    })
</script>

可以看到页面渲染出 LiuZhenghe 26。

如何证明 computed 具有缓存机制?在 fullName 方法中打印一句话“计算了一次!”,在控制台改变 age 的值,再改变 fullName 中计算过的属性值。

可以看到,页面一刷新的时候,打印一遍 “计算了一次!”,改变 age,没有打印这句话,改变 lastName,又打印一遍 “计算了一次!”。

方式二:methods

注意:因为 fullName 这次写到了 methods 中,所以在模板引擎中需要加括号。

<div id="app">{{fullName()}} {{age}}</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            firstName: "Liu",
            lastName: "Zhenghe",
            age: 26
        },
        methods: {
            fullName: function () {
                console.log("计算了一次!");
                return this.firstName + this.lastName;
            }
        }
    })
</script>

可以看到,页面一刷新的时候,打印一遍 “计算了一次!”,改变 age,也打印这句话,改变 firstName 和 lastName,又都打印一遍 “计算了一次!”。

所以,说明 methods 方法是没有缓存机制的,只要改变了数据,就会重新计算一次。

方式三:watch 侦听器

<div id="app">{{fullName}} {{age}}</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            firstName: "Liu",
            lastName: "Zhenghe",
            fullName: "LiuZhenghe",
            age: 26
        },
        watch: {
            firstName: function () {
                console.log("计算了一次!");
                this.fullName = this.firstName + this.lastName;
            },
            lastName: function () {
                console.log("计算了一次!");
                this.fullName = this.firstName + this.lastName;
            }
        }
    })
</script>

在控制台,改变 age,并没有打印出 “计算了一次!”这句话,改变 firstName 和 lastName 的值,发现打印出了这句话,说明 watch 和 computed 一样具有缓存机制,但和 computed 相比,watch 逻辑代码多出很多,所以,当这三种计算方式都能实现计算功能的时候,优先选择 computed。

五、计算属性的 setter 和 getter

computed 有这样一个特性:当他依赖的值发生变化的时候,它就会去重新的计算。

<div id="app">{{fullName}}</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            firstName: "Liu",
            lastName: "Zhenghe",
        },
        computed: {
            fullName: {
                get: function () {
                    return this.firstName + " " + this.lastName
                },
                // set 方法可以接收一个设置后的值,例如在控制台改变 fullName 的值 “app.fullName="Li Zheng"”,将会打印出 “Li Zheng”。
                set: function (value) {
                    console.log(value);
                    // 将设置后的 fullName 值通过空格分开,并存放到数组 arr 中,按照上面给 fullName 设置的值,下边 arr 的值将会打印出 “(2) ["Li", "Zheng"]”
                    var arr = value.split(" ");
                    console.log(arr);
                    this.firstName = arr[0];
                    this.lastName = arr[1];
                }
            }
        }
    })
</script>

通过这个例子,可以知道,在 computed 上,不仅可以通过 get 方法,通过其他的值算出一个新值,同时可以写 set 方法,通过设置一个值,来改变他相关联的一个值,而改变了相关的值后,又使 fullName 的值重新计算。

六、Vue.js 中的样式绑定

样式和数据绑定,实现:点击一次,元素变色,再点击一次,元素颜色变回来。

方式一、class 的对象绑定,借助 class 和对象的形式做样式和数据的绑定。

<div id="app" :class="{activted:isActivted}" v-on:click="changeColor">Hello World</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            isActivted: false,
        },
        methods: {
            changeColor: function () {
                this.isActivted = !this.isActivted;
            }
        }
    })
</script>
<style>
    .activted {
        color: red
    }
</style>

上面代码中,通过给元素绑定点击事件,在点击事件中,改变 isActivted 的值,来确定是否给元素的 class 加 activted,然后给 activted 设置一个样式,来实现点击切换颜色效果。

方式二、:class 中不再写入一个对象,而是写一个数组,在数组中写一个 activted。

<div id="app" :class="[activted]" v-on:click="changeColor">Hello World</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            activted: "",
        },
        methods: {
            changeColor: function () {
                // 用 if 判断实现点击切换效果:
                // if (this.activted === "activted") {
                //     this.activted = "";
                // } else {
                //     this.activted = "activted";
                // };

                // 用三元运算符实现点击切换效果:
                this.active = this.activted === "activted" ? this.activted = "" : this.activted =
                    "activted";
            }
        }
    })
</script>
<style>
    .activted {
        color: red
    }
</style>

在上面代码中,首先将 activted 设置为空,然后在点击事件中通过 if 或三元运算符来判断,当 data 中的 activted 为空时,就设置为 “activted”,当是“activted”时,再设置为空,以此来实现点击切换颜色效果。

方式三、通过 style 来改变样式,:style 中写 js 字符串。

<div id="app" :style="styleObj" v-on:click="changeColor">Hello World</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            styleObj: {
                color: "black"
            }
        },
        methods: {
            changeColor: function () {
                this.styleObj.color = this.styleObj.color === "black" ? "red" : "black";
            }
        }
    })
</script>

上面代码中,将 data 中的样式对象 styleObj 传到 :style 中,在点击事件中,通过改变 styleObj 中的 color 值来实现点击切换颜色效果。

方式四:通过 style 来改变样式,:style 中写数组,数组中还可以挂载多个样式。

<div id="app" :style="[styleObj,{fontSize : '24px'},{fontWeight : '900'}]" v-on:click="changeColor">Hello World
</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            styleObj: {
                color: "black"
            }
        },
        methods: {
            changeColor: function () {
                this.styleObj.color = this.styleObj.color === "black" ? "red" : "black";
            }
        }
    })
</script>

无论是绑定 class 还是 style,都有两种方式,一种是通过对象的方式绑定,一种是通过数组的方式绑定。

七、Vue.js 中的条件渲染

1、条件渲染 v-if 和 v-show 对比

v-if 后面跟一个 js 表达式,它的返回值(true, false)决定了这个元素是否真实的被挂载到页面上。

<div id="app">
    <div v-if="show">Hello World!</div>
    <div v-show="show">Hello World!</div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            show: true
        }
    })
</script>

在 data 中 show 默认为 true,是显示的,可以在控制台中修改一下 show 的值:“app.show = false”,发现两个 dom 不存在了,改为 true,这两个 dom 又显示了。

打开网页,可以看到,无论是 v-if 还是 v-show,如果 data 中的 show 值是 false,那么两个元素都不显示,我们在控制台中查看一下两个元素:

发现,v-if 在页面上就不显示了,而 v-show 元素是存在的,只是样式被加了 “display: none;” ,所以 v-show 的性能更会高一些,因为它不会频繁的去把有个 dom 从页面上删再添加。

2、更复杂的使用 v-if

v-if 和 v-else
<div id="app">
    <div v-if="show">Hello World!</div>
    <!-- 注意,v-if 和 v-else 两个元素中间不能加其他元素,否则条件判断不能生效。 -->
    <div v-else>Bye World!</div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            show: false
        }
    })
</script>

上面代码中,如果 show 的值是 false 的话,就显示 v-else 中的值,需要注意的是 v-if 和 v-else 两个元素中间不能加其他元素,否则条件判断不能生效。

多条件(v-if、v-else-if、v-else)
<div id="app">
    <div v-if="show === 'a'">This is a!</div>
    <div v-else-if="show === 'b'">This is b!</div>
    <div v-else>This is other</div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            show: a
        }
    })
</script>

可以在控制台中改变一下 show 的值,当时 show 的值为 a 时,显示 “This is a”,为 b 时,显示 “This is b”,为其他时,显示 “This is other。”

3、key 值

<div id="app">
    <div v-if="show">
        用户名:<input type="text">
    </div>
    <div v-else>
        邮箱:<input type="text">
    </div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            show: true
        }
    })
</script>

上面代码,因为 show 的值是 true,所以此时页面上显示的是用户名输入框,我们在输入框中输入内容,然后在控制台中改变 show 的值为 flase,发现输入框更换为邮箱了,但是输入框里的内容并没有变,这是因为 Vue 在重新渲染页面的时候,会尽量的复用页面上已存在的 dom,当显示用户名的时候,已经有了一个 input,当切换邮箱名的时候,Vue 会发现以前页面上有一个 input,所以他的机制会尽量的帮你复用页面上的 dom,回去尝试复用这个 input,但是内容并没有被清空。

解决方法:在 input 中加 key 值,例如给用户名加一个 key 值 “key="username"”,邮箱加一个 “key="email"”,此时再改变 show 的值,发现输入框内容被清空了功能也没有任何的 bug 了。当给元素加一个 key 值的时候,Vue 会知道他是页面上唯一的元素,如果两个元素的 key 值不一样,Vue 就不会尝试复用以前的 input 标签了。

<div id="app">
    <div v-if="show">
        用户名:<input type="text" key="username">
    </div>
    <div v-else>
        邮箱:<input type="text" key="email">
    </div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            show: true
        }
    })
</script>

八、Vue.js 中的列表渲染

先来看一下列表循环最基础的内容:

<div id="app">
    <div v-for="item in list">{{item}}</div>
    <div v-for="item of list">{{item}}</div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            list: [
                "one", "two", "three", "four", "five"
            ]
        }
    })
</script>

在 v-for 中,in 和 of 的效果是一样的,可以在 item 后再加一个参数 index,代表索引下标:

<div id="app">
    <div v-for="(item, index) of list">{{item}} --- {{index}}</div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            list: [
                "one", "two", "three", "four", "five"
            ]
        }
    })
</script>

在实际的开发中,为了提升循环显示的性能,我们会给每一个循环项上加唯一的 key 值,可以在循环向上加一个 key 值,因为目前 index 的值是唯一的,所以使用 index 作为 key 值。

<div id="app">
    <div v-for="(item, index) of list" :key="index">{{item}} --- {{index}}</div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            list: [
                "one", "two", "three", "four", "five"
            ]
        }
    })
</script>

但是不推荐这样使用 index 的,因为使用 index 作为 key 值,在平凡操作 DOM 元素相对应的数据的时候,是比较费性能的,可能让 Vue 没法充分的复用 dom 节点。如果不用 index 做 key 值。那用什么呢?

一般在真正的项目中,后端向前端返回数据的时候,list 并不是写死的一个数据,后端反数据的时候,一般会携带一个数据相关的唯一标识符,一般是 id,可能是数据对应的一个随机的数据段,例如:

<div id="app">
    <div v-for="(item, index) of list" :key="item.id">{{item.text}} --- {{index}}</div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            list: [{
                id: "10001",
                text: "one"
            }, {
                id: "10002",
                text: "two"
            }, {
                id: "10003",
                text: "three"
            }],
        }
    })
</script>

这个时候,key 值就没必要是 index 了,可以用 item.id,我们可以参考之前 TodoList 在控制台中给 list 添加数据,可以看到数据添加成功,页面更新了:

如果通过下标添加数据呢?可以在控制台看到数据添加成功,但是页面却没有更新。

到这里,需要讲一个内容,当我们去尝试修改数组里的内容时,不能直接通过下标的形式,只能通过 Vue 提供的几个数组变异方法来操作数组,才能够实现数据发生变化,页面也跟着变这种响应式效果。在 Vue 中一共提供了 7 个数组变异方法来帮助我们操作数组,他们分别是:

回到页面上,例如将第二项做一个替换,可以在控制台做如下操作:

除了变异方法可以改变页面数据的显示,还有一种方法,就是改变引用:

上边数组循环只循环了一个数据,假设有这样一个情况:不仅要根据 list2 循环一个 div,还要根据 list 循环一个 span 标签:

<div id="app">
    <div v-for="(item, index) of list">
        <div>{{item.text}} --- {{index}}</div>
        <span>{{item.text}} --- {{index}}</span>
    </div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            list: [{
                id: "10001",
                text: "one"
            }, {
                id: "10002",
                text: "two"
            }, {
                id: "10003",
                text: "three"
            }],
        }
    })
</script>

如果要想显示一个 span 一个 div 就必须在外层包裹一个 div,否则就会先显示完 div 再显示 span, 假设在需求里就不想让这个 div 存在,有什么办法么?template 占位符,可以把外层 div 改为 template,也可以理解为一个模板占位符,回到页面上,可以看到依然是 div,span 的显示方式,但是最外层的 div 就消失了。

<div id="app">
    <template v-for="(item, index) of list">
        <div>{{item.text}} --- {{index}}</div>
        <span>{{item.text}} --- {{index}}</span>
    </template>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            list: [{
                id: "10001",
                text: "one"
            }, {
                id: "10002",
                text: "two"
            }, {
                id: "10003",
                text: "three"
            }],
        }
    })
</script>

其实这个 template 模板占位符可以帮我们去包裹一些元素,但是在循环的时候并不会被真正的渲染到页面上。

除了数组可以做循环之外,其实还可以对对象做一个循环,接下来看一下对象怎么做循环:

<div id="app">
    <div v-for="item of userInfo">{{item}}</div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            userInfo: {
                name: "liu",
                age: "26",
                gender: "male",
                salary: "secret"
            }
        }
    })
</script>

item 还可以接收其他内容 key,index:

<div id="app">
    <div v-for="(item, key, index) of userInfo">
        {{item}} --- {{key}} --- {{index}}
    </div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            userInfo: {
                name: "liu",
                age: "26",
                gender: "male",
                salary: "secret"
            }
        }
    })
</script>

我们在控制台改变一下 userInfo 中的值:

可以看到,改变 userInfo 中的某个值,页面会更新,但是新添加一个 address 值,数据变了,但页面不会更新,所以当你去便历对象的时候,如果直接动态的往里加值是不好用的,但是如果就是相加那怎么加呢?

可以和数组的方式一样,直接改变他的引用:

通过改变引用这种方式,数据变化了,页面也就变化了。

九、Vue.js 中的 set 方法

先来回顾上一节我们说过的,如果要改变对象 userInfo 中的属性和值,就要通过它的引用来改变,这样才会让页面也更新。

<div id="app">
    <div v-for="(item, key, index) of userInfo">
        {{item}} --- {{key}} --- {{index}}
    </div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            userInfo: {
                name: "liu",
                age: "26",
                gender: "male",
                salary: "secret"
            }
        }
    })
</script>

那除了改变引用是否还有其他方法能在改变数据后页面也更新呢?下面看一下 Vue.js 中的 set 方法。

1、对象中的 set 方法

还是用上的代码,可以通过构造函数来更新 userInfo 中的属性值,例如:“Vue.set(app2.userInfo,"address","Beijing")”,也可以通过实例对象来更新 userInfo 中的属性值,例如 “app2.$set(app2.userInfo,"tel","1234567")”,这两种方法在更新数据后,页面也都会同步更新。

2、数组中的 set 方法

<div id="app">
    <div v-for="item of list">
        {{item}}
    </div>
</div>

<script>
    var app = new Vue({
        el: "#app",
        data: {
            list: [1, 2, 3, 4]
        }
    })
</script>

在控制台中,分别通过全局对象(构造函数)和实例对象来更新 list 中的数据,可以看到这两种方法在更新数据后,页面也都会同步更新。


长得好看的都会关注我的 o(≧v≦)o~~

上一篇下一篇

猜你喜欢

热点阅读