1.cdn:内容分发网络(CDN)是将资源托管到全世界各处的服务器上以实现快速分发。CDN版本对于开发和快速验证比较有用,但是将unpkg应用于生产环境前,需要检查它是否适合你。
2.假值包括false、undefined、null、‘’、NAN。
3.使用v-show两个场景:
频繁切换某些内容;
如果元素包含任何图片,那么仅使用css隐藏父节点可以使浏览器在图片显示之前就加载它,这意味着一旦v-show变成真值,图片就可以显示出来。如果是v-if指令,图片就直到要显示时才开始加载。
4.响应式如何实现:
vue修改了每个添加到data上的对象,当该对象发生变化时vue会收到通知,从而实现响应式。对象的每个属性会被替换为getter和setter方法,因此可以像正常对象一样使用它,但当你修改这个属性时,vue会知道它发生了变化。
5.为对象添加新的属性。
因为getter,settter方法是在vue实例初始化的时候添加的,只有已经存在的属性是响应式的,当为对象添加一个新的属性的时候,直接添加并不会使这个属性成为响应式的。
1 const vm = new Vue({
2 data: {
3 formData: {
4 username: 'someuser'
5 }
6 }
7 });
有几种方法解决这个问题:
(1)最简单的办法是在初始化时对象上定义这个属性,并把它的值设置为undefined。上例中的formData对象会变成下面这样:
1 formData: {
2 username: 'someuser',
3 name: undefined
4 }
(2) 也可以使用Object.assign()来创建一个新的对象然后覆盖原来对象,当需要一次性更新多个属性时,这是最有效的方法:
1 vm.formData = Object.assign({}, vm.formData, {
2 name: 'Some User'
3 });
(3)Vue还提供了Vue.set()方法,可以使用它将属性设置为响应式的:
1 Vue.set(vm.formData, 'name', 'Some User');
在组件内部也可以使用this.$set来调用这个方法。
6.设置数组的元素
不能直接使用索引来设置数组的元素。下面的做法是行不通的:
1 const vm = new Vue({
2 data: {
3 dogs: ['Rex', 'Rover', 'Henrietts', 'Alan']
4 }
5 });
6 vm.dogs[2] = 'Bob'
有两种方法可以解决这一问题。一种是使用.splice( )方法移除旧元素并添加新元素:
vm.dogs.splice(2, 1, 'Bob');
另一种是使用Vue.set( ):
Vue.set(vm.dogs, 2, 'Bob');
7.设置数组的长度
在javascript中,可以设置一个数组的长度,自动让空元素填充数组至该长度或者截掉数组的尾部。不过这个方法不能用于处理data对象中的数组,因为Vue不能检测到该操作对数组的任何更改。
8.到目前为止已经了解如何将数据输出到模板,以及vue的响应式能力如何做到让模板随着数据的跟新而更新。但这只是单向数据绑定。试着运行下面的代码,你会发现inputText会保持不变。输入框下面的文本也会保持不变。
1 <div id="app">
2 <input type="text" :value="inputText">
3 <p>inputText: {{inputText}}</p>
4 </div>
5 <script>
6 new Vue({
7 el: '#app',
8 data: {
9 inputText: 'initial value'
10 }
11 })
12 </script>
可以使用v-model指令,它作用于输入框元素,将输入框的值绑定到data对象的对应属性上,因此输入框不但会接收data上的初始值,而且当输入框内容更新时,data上的属性值会被更新。
1 <div id="app">
2 <input type="text" v-model="inputText">
3 <p>inputText: {{inputText}}</p>
4 </div>
5 <script>
6 new Vue({
7 el: '#app',
8 data: {
9 inputText: 'initial value'
10 }
11 })
12 </script>
9.method妙用
(1)将代表状态的数字-转换为可读的、描述真实状态的字符串
1 <div id="app">
2 <p>当前状态: {{statusFromId(status)}}</p>
3 </div>
4 <script>
5 new Vue({
6 el: '#app',
7 data: {
8 status: 2
9 },
10 methods: {
11 statusFromId(id) {
12 const status = ({
13 0: '睡觉',,
14 1: '吃饭',,
15 2: '学习vue'
16 })[id];
17 return status || '未知状态:' +id;
18 }
19 }
20 })
21 </script>
(2)过滤for循环中的数据,避免v-for和v-if混用
1 <div id="app">
2 <ul>
3 <li v-for="number in filterPositive(numbers)">{{number}}</li>
4 </ul>
5 </div>
6 <script>
7 new Vue({
8 el: '#app',
9 data: {
10 numbers: [-5, 0, 2, -1, 1, 0.5]
11 },
12 methods: {
13 filterPositive(numbers) {
14 return numbers.filter((number)=> number > 0); // [2, 1, 0.5]
15 }
16 }
17 })
18 </script>
10. 在vue2.0中,mounted钩子触发时并不保证元素已经被添加到DOM上。如果想保证元素已经被添加,可以调用Vue,nextTick()方法,也可以通过this.$nextTick()调用,并传入一个回调函数,在回调函数中添加需要在元素被添加到DOM之后运行的代码。
1 <div id="app">
2 <p>Hello world</p>
3 </div>
4 <script>
5 new Vue({
6 el: '#app',
7 mounted() {
8 // 元素可能还没添加到DOM上
9 this.$nextTick(()=>{
10 // 确定元素已经被添加到DOM上了
11 })
12 }
13 })
14 </script>
11. 使用自定义指令directive, 来实现一个闪烁效果:
1 <body>
2 <div id="app">
3 <p v-blick>我会闪烁</p>
4 </div>
5 </body>
6 <script>
7 new Vue({
8 el: '#app',
9 data: {},
10 directives: {
11 'blick': {
12 bind(el) {
13 let isVisible = true;
14 setInterval(() => {
15 isVisible = !isVisible;
16 el.style.visibility = isVisible ? 'visible' : 'hidden';
17 }, 1000)
18 }
19 }
20 }
21 })
22 </script>
12. prop使用和.sync修饰符
如果prop的值不是字符串,那么就必须使用v-bind指令。
<display-number :number = "10"></display-number>
数据通过prop从父级组件传递给子组件中,当父级组件中的数据更新时,传递给子组件的prop也会更新。但是你不可以在子组件中修改prop。这就是所谓的单向下行绑定,防止子组件在无意中改变父级组件的状态。
然而,双向数据绑定在某种情况下可能很有用。如果想要使用双向绑定,可以使用一个修饰符来实现 : .sync修饰符。它只是一个语法糖:
<count-from-number :number.sync="numberToDisplay" />
13.自定义输入组件与v-model
与.sync修饰符相似,可以在组件上使用v-model指令来创建自定义输入组件。这里同样也是一个语法糖。请看示例:
<input-username v-model="username" />
上面的代码等效于:
<input-username :value="username" @input="value => username=value" />
14.响应路由变化
当/user/1234 与/user/5678 相互切换时,其中相同的组件会被重用,于是第一章所涉及到的生命周期钩子,诸如mounted,都不会被调用。不过,你可以使用beforeRouteUpdate导航守卫在URL动态部分变化时运行一些代码。
我们创建一个PageUser组件,它在挂载的时候会调用一次API,并且在路由变化时还会再调用一次:
<template>
<div v-if="state === 'loading'">
loading user...
</div>
<div>
<h1>user: {{userInfo.name}}</h1>
</div>
</template>
<script>
export default {
data: ()=> ({
state: 'loading',
userInfo: undefined
}),
mounted() {
this.init();
},
beforeRouteUpdate(to, from, next) {
this.state = 'loading';
this.init();
next();
},
method: {
init() {
fetch(`/api/user/${this.$route.params.userId}`)
.then((res)=> res.json())
.then((data)=> {
this.userInfo = data;
});}
}
}
}
</script>
15.路由参数作为组件属性传入
除了在组件中使用this.$route.params,还可以让vue-router将params作为路由组件的props传入。以如下组件为例:
const PageUser = {
template: '<p>ID: {{ $route.params.userId }}</p>'
};
const router = new VueRouter({
routes: [{
path: '/user/:userId ',
component: PageUser
}]
});
当导航至/user/1234的时候,‘ID:1234’就会被输出到页面上。
要想让vue-router改为将userId作为组件的一个属性传入,你可以在路由中指定props:true
const PageUser = {
props: ['userId],
template: '<p>user ID: {{ userId }}</p>'
};
const router = new VueRouter({
routes: [
path: '/user/:userId',
component: PageUser,
props: true
]
});
使用props代替$route.$params的好处是:组件与vue-router不再紧密耦合。设想一下,将来你想在一个页面上展示多个用户,使用第一个例子的代码就会很棘手,但使用第二个例子的代码就会变得很简单,因为只要在另一个页面调用该组件就好了,就像它是一个与路由无关的通用组件那样。
16.vue-router中的tag属性
<router-link to="/user/1234" tag="li">go to user 1234</router-link>
这会在页面上渲染出如下结果:<li> go to user 1234 </li>
由此,在它上面悬停也就不会给你带来任何关于这个链接的消息,也不能通过鼠标右键在新窗口打开这个链接;
为了解决这个问题,可以在<router-link>元素里面加上锚点标签:
<router-link to="/user/1234" tag="li"><a>go to user 1234</a></router-link>
现在,渲染出来的html就是下面这样:
<li><a href="/user/1234" >go to user 1234</a></li>
如果想给<router-link>添加一个事件处理器,可以使用.native修饰符来监听:
<router-link to="/blog" @click.native="handleClick">blog</router-link>
17.导航守卫
当你维护的是一个拥有大量路由的网站,于是会发现另一个很有用的特性,它就是路由元信息。你可以在路由上添加一个meta属性,并在守卫那里重新获取它。例如,在account路由上设置一个requiresAuth属性,然后在守卫中查看该属性:
const router = new VueRouter({
routes: [{
path: '/account',
component: PageAccount,
meta: {
requiresAuth: true
}
}]
});
router.beforeEach((to, from, next)=> {
if (to.meta.requiresAuth) {
next('/login');
} else {
next();
}
})
当使用嵌套路由时,to.meta指向的是子路由的元信息,而非其父路由。也就是说,如果你在/account上添加了meta对象,而用户访问的是/account/email,则所获得的meta对象是关于该子路由的,而非父路由。可以通过遍历to,matched的方式来曲线救国,
它同样也包含了父路由的元信息:
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some((record) => {
return record.meta.requiresAuth;
})
if (to.meta.requiresAuth) {
next('/login');
} else {
next();
}
})
18.afterEach,可用于设置页面标题
const router = new VueRouter({
routes: [{
path: '/blog',
components: PageBlog,
meta: {
title: 'welcome to my blog'
}
}]
});
router.afterEach((to) => {
document.title = to.meta.title;
});
19.使用vuex和websocket,实现用户在页面上所拥有的的消息数量
组件代码:
const NotificationCount = { template: `<p>messages: {{messageCount}}</p>`, computed: { messageCount() { return this.$store.state.messages.length; } }, mounted() { this.$store.dispatch('getMessages'); } };
然后下面使我们的vuex store(store/index.js)
let ws;
export default new Vuex.Store({
state: {
messages: []
},
mutations: {
setMessages (state, messages) {
state.messages = messages;
}
},
actions: {
getMessages ({ commit }) {
if (ws) { return ; }
ws = new WebSocket('/api/message');
ws.addEventListener('message', (e)=> {
const data = JSON.parse(e.data);
commit('setMessages ', data.message);
});
}
}
});
阮一峰webSocket 教程: http://www.ruanyifeng.com/blog/2017/05/websocket.html?utm_source=tuicool&utm_medium=referral
实例对象的onmessage属性,用于指定收到服务器数据后的回调函数。