接[Vue2从入门到出门](Vue2从入门到出门 - 掘金 (juejin.cn)),实在放不下了兄弟萌。
路由
了解路由之前,我们先了解一下单页应用:
单页应用(SPA)
SPA(Single Page web Application),指只有一个主页面的应用,浏览器一开始会加载必须的HTML,CSS和JavaScript,所有的操作都在这张页面上完成。
优点:
- 用户操作体验好,用户不用刷新页面,整个交互通过Ajax操作进行
- 前后端分离清晰,前端通过HTTP请求获取数据
缺点:
- 首页加载慢,会将页面所需内容打包统一加载
- 对SEO不友好,所有内容都在一个页面上动态替换展示
SEO
SEO(Search Engine Optimization)搜索引擎优化:利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名,以获得收益的方法。
前端路由可以帮助我们在仅有一个页面的情况下,为SPA中的各个视图匹配一个唯一标识。
常规
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<router-link to="/mine">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>Hello {{name}}</div>`,
data(){
return{
name:'WDY'
}
}
})
Vue.component('mine',mine)
const router = new VueRouter({
routes:[
{path:'/',component:home},
{path:'/mine',component:mine}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
多级路由
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<router-link to="/mine">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link to='/mine/me'>me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY'
}
}
})
Vue.component('mine',mine)
const me = Vue.extend({
template:`<div>我是多级理由me</div>`,
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{path:'/',component:home},
{
path:'/mine',
component:mine,
children:[
{
path:'me',
component:me
},
{
path:'mee',
component:mee
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
第一层:
第二层:
命名路由
给路由起一个别名,即用别名替代路径也可正常使用:
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<!-- <router-link to="/mine">Go to Mine</router-link> -->
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link to='/mine/me'>me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY'
}
}
})
Vue.component('mine',mine)
const me = Vue.extend({
template:`<div>我是多级理由me</div>`,
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{path:'/',component:home},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
path:'me',
component:me
},
{
path:'mee',
component:mee,
name:'wo'
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
重定向
当我们输入一个网址时,它会被指向我们所重定向的那个网址:
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<!-- <router-link to="/mine">Go to Mine</router-link> -->
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link to='/mine/me'>me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY'
}
}
})
Vue.component('mine',mine)
const me = Vue.extend({
template:`<div>我是多级理由me</div>`,
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/',
redirect:'/mine'
},
{
path:'/home',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
path:'me',
component:me
},
{
path:'mee',
component:mee,
name:'wo'
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
输入:
敲回车,会跳转到我们设置的mine页面:
数据传输
query
栗子使用了query进行数据传递,同时也使用了命名路由的语法:
- 传递后会形成新的路径
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<!-- <router-link to="/mine">Go to Mine</router-link> -->
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY'
}
}
})
Vue.component('mine',mine)
const me = Vue.extend({
template:`<div>我是多级理由{{$route.query.name}}</div>`,
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/',
redirect:'/mine'
},
{
path:'/home',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
path:'me',
component:me,
name:'wo'
},
{
path:'mee',
component:mee,
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
params
栗子使用了params进行数据传递,同时也使用了命名路由的语法:
- 传递后会形成新的路径
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<!-- <router-link to="/mine">Go to Mine</router-link> -->
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',params:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY',
age:100000
}
}
})
Vue.component('mine',mine)
const me = Vue.extend({
template:`<div>我是多级理由{{$route.params.name}}--{{$route.params.age}}</div>`,
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/',
redirect:'/mine'
},
{
path:'/home',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me/:name/:age',
component:me
},
{
path:'mee',
component:mee,
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
动态路由
query与params进行数据传递又称为动态路由,注意区分两者路由格式的配置
props
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<!-- <router-link to="/mine">Go to Mine</router-link> -->
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY',
age:100000
}
}
})
Vue.component('mine',mine)
const me = Vue.extend({
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby']
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/',
redirect:'/mine'
},
{
path:'/home',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me',
component:me,
props($route){
return{
name:$route.query.name,
age:$route.query.age,
hobby:'eat'
}
}
},
{
path:'mee',
component:mee,
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
方法二:
以true和false设定props,当为true时,可以传递,当为false时,不会传递。该方式使用params传参。
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<!-- <router-link to="/mine">Go to Mine</router-link> -->
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',params:{name:name,age,hobby}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY',
age:100000,
hobby:'eat'
}
}
})
Vue.component('mine',mine)
const me = Vue.extend({
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby']
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/',
redirect:'/mine'
},
{
path:'/home',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me/:name/:age/:eat',
component:me,
props:true
},
{
path:'mee',
component:mee,
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
编程式路由导航
借助router-link实现记录替换(replace):不加replace默认为push
<div id="app">
<p>
<router-link replace to="/">Go to Home</router-link>
<router-link replace :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
<button @click='forward'>前进</button>
<button @click='back'>后退</button>
<button @click='go'>go</button>
</div>`,
data(){
return{
name:'WDY',
age:100000,
}
},
methods:{
forward(){
this.$router.forward()
},
back(){
this.$router.back()
},
go(){
this.$router.go(2)
}
}
})
Vue.component('mine',mine)
const me = Vue.extend({
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby']
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/home',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me',
component:me,
props($route){
return{
name:$route.query.name,
age:$route.query.age,
hobby:'eat'
}
}
},
{
path:'mee',
component:mee,
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
不借助router-link实现路由跳转:
| 常用 | 作用 |
|---|---|
| forward | 前进 |
| back | 后退 |
| go(参数) | 前进多少或后退多少 |
| push | 追加历史记录 |
| replace | 替换当前记录 |
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<!-- <router-link to="/mine">Go to Mine</router-link> -->
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
<button @click='forward'>前进</button>
<button @click='back'>后退</button>
<button @click='go'>go</button>
</div>`,
data(){
return{
name:'WDY',
age:100000,
}
},
methods:{
forward(){
this.$router.forward()
},
back(){
this.$router.back()
},
go(){
this.$router.go(2)
}
}
})
Vue.component('mine',mine)
const me = Vue.extend({
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby']
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/home',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me',
component:me,
props($route){
return{
name:$route.query.name,
age:$route.query.age,
hobby:'eat'
}
}
},
{
path:'mee',
component:mee,
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
缓存路由(keep-alive)
包裹动态组件时,会缓存不活动的组价实例,而不是销毁它们。可以用来缓存组件,避免多次加载相同的组件,减少性能消耗,提高用户体验。
| 属性 | 作用 |
|---|---|
| include | 字符串或正则表达式,只有名称匹配的组件会被缓存 |
| exclude | 字符串或正则表达式,任何名称匹配的组件都不会被缓存 |
| max | 最多可以缓存多少组件实例 |
使用keep-alive缓存路由时,一定给组件命名:
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<keep-alive include='me'>
<router-view></router-view>
</keep-alive>
</div>`,
data(){
return{
name:'WDY',
age:100000,
}
},
methods:{
}
})
Vue.component('mine',mine)
const me = Vue.extend({
name:'me',
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby'],
beforeDestroy(){
console.log('me将被销毁')
},
destroyed(){
console.log('me已经被销毁')
}
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`,
beforeDestroy(){
console.log('mee将被销毁')
},
destroyed(){
console.log('mee已将被销毁')
}
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/home',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me',
component:me,
props($route){
return{
name:$route.query.name,
age:$route.query.age,
hobby:'eat'
}
},
},
{
path:'mee',
component:mee,
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
切换me组件与mee组件:
失活与激活
组件当跳入页面就会激活,当跳出页面就会失活
| 属性 | 作用 |
|---|---|
| activated | 组件激活 |
| deactivated | 组件失活 |
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<keep-alive include='me'>
<router-view></router-view>
</keep-alive>
</div>`,
data(){
return{
name:'WDY',
age:100000,
}
},
methods:{
}
})
Vue.component('mine',mine)
const me = Vue.extend({
name:'me',
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby'],
activated(){
console.log('me组件被激活')
},
deactivated(){
console.log('me组件已经失活')
},
beforeDestroy(){
console.log('me将被销毁')
},
destroyed(){
console.log('me已经被销毁')
}
})
Vue.component('me',me)
const mee = Vue.extend({
template:`<div>我是多级路由mee</div>`,
beforeDestroy(){
console.log('mee将被销毁')
},
destroyed(){
console.log('mee已将被销毁')
}
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/home',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me',
component:me,
props($route){
return{
name:$route.query.name,
age:$route.query.age,
hobby:'eat'
}
},
},
{
path:'mee',
component:mee,
}
]
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
历史记录模式(hash&history)
hash(默认)
URL中#及后面的部分为hash值,它虽然出现在URL中,但不会被包含在HTTP请求中。
history
URL常见的格式/
路由元信息
每个路由携带的信息,可以与守卫搭配使用。
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
name:'home',
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
name:'mine',
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY',
age:100000,
}
},
methods:{
}
})
Vue.component('mine',mine)
const me = Vue.extend({
name:'me',
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby'],
})
Vue.component('me',me)
const mee = Vue.extend({
name:'mee',
template:`<div>我是多级路由mee</div>`,
})
Vue.component('mee',mee)
const router = new VueRouter({
mode:'history',
routes:[
{
path:'/',
component:home,
meta:{
login:true
}
},
{
path:'/mine',
name:'wode',
component:mine,
meta:{
login:true
},
children:[
{
name:'wo',
path:'me',
component:me,
props($route){
return{
name:$route.query.name,
age:$route.query.age,
hobby:'eat'
}
},
},
{
path:'mee',
component:mee,
}
],
}
]
})
router.beforeEach((to,from,next)=>{
if(to.meta.login == true){
next()
}
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
Go to Home与Go to Mine可以正常转换,而me与mee不能正常显示其信息。
路由守卫
路由跳转过程中的一些钩子函数,在路由跳转时进行一些操作。类似于组件的生命周期钩子。
全局守卫
全局前置守卫(router.beforeEach((to,from,next)=>{}))
初始化时被调用,每次路由切换之前被调用。
| 属性 | 作用 |
|---|---|
| to | 即将进入目标的路由 |
| from | 当前导航将要离开的路由 |
| next | 函数,决定是否展示页面(可以是判断条件等) |
全局解析守卫(router.beforeResolve((to,from,next)=>{}))
组件被解析之后调用。
全局后置守卫(router.afterEach((to,from)=>{}))
初始化时被调用,每次路由切换之后被调用。
| 属性 | 作用 |
|---|---|
| to | 即将进入的目标路由 |
| from | 当前导航要离开的路由 |
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
name:'home',
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
name:'mine',
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY',
age:100000,
}
},
methods:{
}
})
Vue.component('mine',mine)
const me = Vue.extend({
name:'me',
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby'],
})
Vue.component('me',me)
const mee = Vue.extend({
name:'mee',
template:`<div>我是多级路由mee</div>`,
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me',
component:me,
props($route){
return{
name:$route.query.name,
age:$route.query.age,
hobby:'eat'
}
},
},
{
path:'mee',
component:mee,
}
]
}
]
})
router.beforeEach((to,from,next)=>{
console.log(to)
console.log(from)
next()
})
router.afterEach((to,from)=>{
console.log(to)
console.log(from)
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
独享守卫(beforeEnter((to,from,next)=>{}))
与全局守卫用法相同,但是只针对一个页面:
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
name:'home',
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
name:'mine',
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY',
age:100000,
}
},
methods:{
}
})
Vue.component('mine',mine)
const me = Vue.extend({
name:'me',
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby'],
})
Vue.component('me',me)
const mee = Vue.extend({
name:'mee',
template:`<div>我是多级路由mee</div>`,
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me',
component:me,
props($route){
return{
name:$route.query.name,
age:$route.query.age,
hobby:'eat'
}
},
beforeEnter:((to,from,next)=>{
console.log(to)
console.log(from)
next()
})
},
{
path:'mee',
component:mee,
}
],
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
组件内守卫
beforeRouteEnter((to,from,next)=>{})
在组件创建前触发,此时组件还没有创建成功,不能访问this实例
beforeRouteUpdate((to,from,next)=>{})
当前路由改变,但是该组件被复用
beforeRouteLeave((to,from,next)=>{})
离开组件时触发
<div id="app">
<p>
<router-link to="/">Go to Home</router-link>
<router-link :to="{name:'wode'}">Go to Mine</router-link>
</p>
<router-view></router-view>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const home = Vue.extend({
name:'home',
template:`<div>Hello World</div>`,
})
Vue.component('home',home)
const mine = Vue.extend({
name:'mine',
template:`<div>
Hello {{name}}
<ul>
<li>
<router-link :to="{name:'wo',query:{name:name,age}}">me</router-link>
</li>
<li>
<router-link to='/mine/mee'>mee</router-link>
</li>
</ul>
<router-view></router-view>
</div>`,
data(){
return{
name:'WDY',
age:100000,
}
},
methods:{
}
})
Vue.component('mine',mine)
const me = Vue.extend({
name:'me',
template:`<div>我是多级理由{{name}}--{{age}}---{{hobby}}</div>`,
props:['name','age','hobby'],
beforeRouteEnter(to,from,next){
console.log(to)
console.log(from)
next()
},
beforeRouteLeave(to,from,next){
console.log('-----------------leave')
console.log(to)
console.log(from)
next()
}
})
Vue.component('me',me)
const mee = Vue.extend({
name:'mee',
template:`<div>我是多级路由mee</div>`,
})
Vue.component('mee',mee)
const router = new VueRouter({
routes:[
{
path:'/',
component:home
},
{
path:'/mine',
name:'wode',
component:mine,
children:[
{
name:'wo',
path:'me',
component:me,
props($route){
return{
name:$route.query.name,
age:$route.query.age,
hobby:'eat'
}
},
},
{
path:'mee',
component:mee,
}
],
}
]
})
const app = new Vue({
el:'#app',
router:router,
})
</script>
Vue脚手架
安装(npm版)
Vue CLI 4.x 需要 Node.js v8.9 或更高版本 (推荐 v10 以上)。你可以使用 n,nvm 或 nvm-windows 在同一台电脑中管理多个 Node 版本
- npm install -g @vue/cli
- 创建项目,选择版本
到这儿一个简单的脚手架就安装好了:
| 文件 | 存放 |
|---|---|
| node_modules | node安装依赖包,即npm或yarn安装东西的仓库 |
| pubic | 存放静态资源 |
| src | 资源文件夹,存放项目代码的文件夹 |
| .gitignore | git上传文件时,不上传的文件写在此处 |
| babel.config.js | 配置文件,用于兼容更多浏览器 |
| jsconfig.json | 指定根文件和JavaScript语言服务提供的功能选项 |
| package.json | 项目基本信息 |
| package-lock.json | 锁定安装的版本上传到git |
| README.md | 描述,说明性文件 |
| vue.config.js | 可选配置文件 |
| src下文件 | 存放 |
|---|---|
| asset | 静态资源 |
| components | 公共组件存放 |
| router | 路由 |
| App.vue | 主组件 |
| main.js | 项目核心文件,实例,应用的插件等 |
Vuex
Vuex是Vue的状态管理模式,可以将其理解为一个容器,里面存放着应用中的大部分状态(state)。
| 概念 | 作用 |
|---|---|
| State | 存储所有共享的状态信息 |
| Getters | 对数据进行一些处理 |
| Mutations | 对数据进行操作 |
| Actions | 包含异步操作 |
| Modules | 分模块管理数据 |
下面是一个简单的栗子:
<div id="app">
{{$store.state.sum}}
<button @click="add">+</button>
<button @click="actionsAdd">actions+</button>
</div>
<script>
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const store = new Vuex.Store({
state:{
sum:0
},
actions:{
actionsAdd(context,value){
context.commit('add',value)
}
},
mutations:{
add(state,value){
state.sum += value
}
}
})
const app = new Vue({
el:'#app',
store:store,
data:{
num:1
},
methods:{
add(){
this.$store.commit('add',this.num)
},
actionsAdd(){
this.$store.dispatch('actionsAdd',this.num)
}
}
})
</script>
两个按钮均可实现加一
拓展
响应式原理
创建Vue实例时,Vue会遍历data中的属性(即已经存在的属性),之后用Object.defineProperty将这些property转化为getter/setter,并在内部让Vue能追踪依赖,在property被访问和修改时通知变更。每个实例都有一个watcher实例,他会在属性渲染的过程中把property记录为依赖,之后当setter触发时,会通知watcher,从而使它相关联的组件重新渲染。
单向数据流
Vue提倡单向数据流,即数据总是从父组件流向子组件,子组件不能对父组件传来的数据进行修改,只能通过请求的方式让父组件对数据进行修改($emit)从而达到更新数据的目的。