- 主要针对笔者在学习中遇到的一些疑问进行记录
- 以前一直以为概念是不太重要的东西,所以一直疲于记录,但是最近发现这些原理的概念还是要在以后的学习和使用中不断反复琢磨才能更加灵活的使用,因此会在后期的学习中专门记录。
Vue 生命周期
从图中我们可以看到Vue运行的整个生命周期以及各个阶段的动作。
- beforeCreate
组件实例刚刚被创建,组件属性计算之前,如data属性等;
- created
组件实例创建完成,属性已绑定,完成了数据的观测,但是DOM结构还没有生成(尚未挂载),$el属性还不存在,不可用;
- beforeMount
模板编译/挂载之前
- mounted
模板编译/挂载之后,el挂载到实例上后调用,业务逻辑一般会在这里开始;
- beforeUpdate
组件更新之前
- updated
组件更新之后
- activated
组件被激活时调用:for keep-alive
- deactivate
组件被移除时调用:for keep-alive
- beforeDestory
组件销毁前调用,主要解绑一些使用addEventListener监听的事件;
- destoryed
组件销毁后调用
Vue插值
- 数据的展示使用{{}},括号里面可以包括data里面的数据;
- 如果有的时候想输出HTML,而不是将数据解释后的纯文本,可以使用v-html ;
<div id="app">
<span v-html="link"></span>
</div>
<script>
var app = new Vue{{
el:"#app",
data:{
link:'<a href="#">只是一个链接</a>'
}
}}
</script>
link的内容会被渲染为一个a标签,而不是纯文本,为了防止XSS攻击,可以将“<>”进行转义;
- 如果想显示{{}}标签,而不进行替换,使用v-pre即可跳过这个元素和他的子元素的编译过程;
<span v-pre>{{hello,I'm 不会被编译}}</span>
Vue过滤器
- Vue支持在{{}}插入的值的尾部添加一个管道符'|'来对数据进行过滤,用来格式化文本,如字母全部大写,货币千位或者逗号分隔符,可以自定义过滤的规则,通过给vue实例添加filters来设置;
<template>
<span>{{date|formatDate}}</span>
</template>
<script>
var app = new Vue{{
el:"#app",
data:{
link:'<a href="#">只是一个链接</a>',
date:new Date(),
},
filters:{
//过滤的方法
formatDate:function(value){
let date = new Date(value);
var year = date.getFullYear();
var month = date.getMonth()+1;
var day = date.getDate();
return year+"-"+month+"-"+day;
}
}
}}
</script>
过滤器也可以串联,而且可以接收参数
<!-- 串联 -->
1. {{message |filterA | filterB}}
<!-- 接收参数 -->
2. {{message |filterA('arg1',arg2")}}
内置指令
- v-cloak
不需要表达式,它会在Vue实例结束编译时从绑定的HTML元素上移除,经常和CSS的display:none配合使用;
- v-cloak是一个解决初始化慢导致页面闪动的方法;
- v-once
定义它的元素或组件只渲染一次,包括元素和组件的所有子节点;首次渲染后,不再随数据的变化重新渲染,被视为静态内容。
- v-if, v-else-if,v-else
v-else-if要紧跟v-if.v-else要紧跟v-else-if或者v-if
- v-show
v-show 的用法和v-if基本一致,不过v-show改变元素的display属性,v-show表示的值是false时,元素会隐藏;
- v-show不能再<template>上使用
v-show和v-if的比较:
- v-if才是真正的条件渲染,他会根据表达式适当的销毁或重建元素及绑定元素的事件或子组件,只要当条件第一次为真时才开始编译;
- v-show只是简单的css属性切换,无论条件真与否,都会被编译。v-if更适合条件不经常改变的场景,因为切换开销相对较大,而v-show适用于频繁切换条件;
- v-for
- 数组列表循环
<template>
<div>
<ul v-for="item in books">
<!-- 如果需要索引可以使用如下方式 -->
<!-- <ul v-for="(item,index) in books"> -->
<li>{{item.name}}</li>
</ul>
</div>
</template>
<script>
export default{
data(){
return{
books:[
{name:'<Vue实战>'},
{name:'<Javascript实战>'},
{name:'<CSS实战>'},
]
}
}
}
</script>
- 对象遍历
<template>
<div>
<span v-for="(val,key,index) in bookInfo">{{index}}-{{key}}- {{val}}</span>
</div>
</template>
<script>
export default{
data(){
return{
bookInfo: {
name:'<Vue实战>',
edition:1.2.3,
author:'wang yan'
},
}
}
}
</script>
数组更新
- 改变数组的方法: push(),pop(),shift(),unshift(),splice(),sort(),reverse()
- 不改变数组的方法: filter(),concat(),slice()
这些数组的用途可以参见MDN[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter]
- 通过索引直接设置项和修改数组长度都不会触发视图更新,可以使用set方法
Vue.set(app.books,3,{
name:'Vue 设置数据'
})
Prop
-
slot
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译
keep-alive
要求被切换到的组件都有自己的名字,不论是通过组件的name选项还是局部/全局注册;
Prop
include:字符串或者正则表达式,只有匹配的组件会被缓存
exclude:字符串或者正则表达式,任何匹配的组件都不会被缓存
用法:
- 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 transition相似,keep-alive是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
- is特性:
Vuex
- action 提交的是 mutation,而不是直接变更状态。
- action 可以包含任意异步操作。
- action 通过 store.dispatch 方法触发。
Vue Router
- this.$route.query 路由查询字符串
- this.$route.hash 路由的hash值
- this.$route.params 路由的的参数
- router.push({ name: 'user', params: { userId }}) == router.push({ path:
/user/${userId}
})
- 使用props将组件和路由解耦
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{
path: '/user/:id',
component: User,
props: true
},
// 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
- History模式
正常情况下都需要后端配合着使用
- node js 使用的是connect-history-api-fallback
导航守卫
- router.beforeEach 注册一个全局前置守卫
router.beforeEach((to,from,next)=>{
//...
})
1.next:Function 一定要通过调用该方法来resolve这个钩子。执行结果依赖next方法的调用参数;
2.next()进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是confirmed;
3.next(false)中断当前的导航。如果浏览器的URL改变了,那么URL地址会重置到from路由对应的地址;
4.next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个
新的导航。你可以向 next传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的
选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
5.next(error): 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传
递给 router.onError() 注册过的回调。
6.确保要调用 next 方法,否则钩子就不会被 resolved
router.beforeResolve 注册一个全局守卫,这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
全局后置钩子:这些钩子不会接受next函数也不会改变导航本身
路由独享的守卫 beforeEnter
组件内的守卫:
beforeRouteEnter(to,from,next)
在渲染该组件的对应路由被confirm前调用,不能访问组件实例this,因为当守卫执行前,组件实例还没被创建
- beforeRouteUpdate (to,from,next)
在当前路由改变,但是该组件被复用时调用,可以访问组件实例this,
eg: 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
- beforeRouteLeave(to,from,next)
导航离开该组件的对应路由时调用,可以访问组件实例this
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
路由元信息
- 常常被用来验证登录权限以及设置页面的title
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: {
requiresAuth: true,
title:'Bar page'
}
}
]
}
]
})
一个路由匹配到的所有路由记录会暴露在route.matched数组
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!auth.loggedIn()) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // 确保一定要调用 next()
}
})
数据获取
- 导航完成之后获取
先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。
- 导航完成之前获取
导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。
从技术角度讲,两种方式都不错 —— 就看你想要的用户体验是哪种。