一、路由vue-router
后端路由:对于普通的网站,所有的超链接都是URL地址,URL地址对应服务器上的资源;
前端路由:对于单页面应用程序,主要通过URL中的hash(#)来实现页面跳转,HTTP请求中不会包含hash相关的内容。
插件下载:https://github.com/vuejs/vue-router,https://unpkg.com/vue-router/dist/vue-router.js
在Vue后面加载vue-router,它会自动安装。
<script src="lib/vue.js"></script>
<script src="lib/vue-router.js"></script>
1、路由的基本使用
<div id="app">
<!-- 点击a链接,修改url地址,Vue实例上的router监听到url地址的改变,展示对应组件 -->
<!-- <a href="#/foo">Go To Foo</a> -->
<!-- <a href="#/bar">Go To Bar</a> -->
<!-- <router-link>默认会被渲染成一个<a>标签,通过传入to属性指定链接地址 -->
<router-link to="/foo">Go To Foo</router-link>
<router-link to="/bar">Go To Bar</router-link>
<!-- 路由出口,路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
<script>
// 1.定义(路由)组件
const Foo={template:'<div>foo</div>'};
const Bar={template:'<div>bar</div>'};
// 2.定义路由
// path:监听的路由链接地址。component:要展示的组件,是一个模板对象,不能是组件名
const routes=[
{path:'/foo',component:Foo},
{path:'/bar',component:Bar}
];
// 3.创建router实例,配置路由
const router=new VueRouter({
routes // 相当于routes:routes
});
// 4.创建Vue实例,注册路由
const vm=new Vue({
el:'#app',
router // 注册路由,监听url地址的变化,展示对应组件
});
</script>
2、重定向和别名
重定向:当用户访问/a时,url将会被替换成/b,然后匹配路由为/b,如用于使根路径重定向为显示某个组件。重定向通过routes配置来完成。
const routes=[
{path:'/',redirect:'/foo'}, // 重定向
{path:'/foo',component:Foo}
];
别名:/a的别名是/b意味着,当用户访问/b时,url保持为/b,但路由匹配为/a,和访问/a一样。
const routes=[
{path:'/a',component:A,alias:'/b'}
];
3、<router-link>
tag:使用tag属性指定router-link渲染的标签类型,默认值'a'。还是会监听点击,触发导航。
linkActiveClass:这是路由构造函数中的选项,设置链接激活时使用的CSS类名,默认值"router-link-active"。通过该类名可设置路由高亮的样式。
4、编程式导航
除了使用<router-link>创建a标签来定义导航链接,还可以借助router的实例方法,通过编写代码来实现。
想要导航到不同的URL,使用router.push方法(在Vue实例内部使用this.$router.push),点击<router-link>时,该方法会在内部调用。
router.push('home') // 字符串
router.push({path:'home'}) // 对象
router.push({name:'user',params:{userId:123}}) // 命名的路由
router.push({path:'register',query:{plan:'private'}}) // 带查询参数,变成 /register?plan=private
router.push方法会向history栈添加一个新的记录,当用户点击浏览器后退按钮时,则回到之前的URL。
router.go(n)方法的参数是一个整数,表示在history记录中向前或者后退多少步,类似window.history.go(n)。
5、路由组件传参
(1)? & $route.query
使用查询字符串给路由传递参数,不需要修改路由规则的path属性。
<router-link to="/foo?id=10&name=cong">Go To Foo</router-link>
const foo={
template:'<div>Foo--{{$route.query.id}}--{{$route.query.name}}</div>',
created(){
console.log(this.$route.query.id);
}
}
(2)/ : $route.params
<router-link to="/foo/10/cong">Go To Foo</router-link>
const foo={
template:'<div>Foo--{{$route.params.id}}--{{$route.params.name}}</div>',
created(){
console.log(this.$route.params.id);
}
}
const routes=[
{path:'/foo/:id/:name',component:foo}
];
(3)props
6、嵌套路由
<div id="app">
<router-link to="/user">User</router-link>
<router-view></router-view>
</div>
<template id="user">
<div>
<h3>最高级路由</h3>
<router-link to="/user/profile">Profile</router-link> <!-- 嵌套<router-link> -->
<router-view></router-view> <!-- 嵌套<router-view> -->
</div>
</template>
<script>
const User={
template:'#user'
};
const Profile={ // 嵌套路由的组件
template:'<div>被嵌套的路由</div>'
};
const router=new VueRouter({
routes:[
{
path:'/user',
component:User,
children:[ // 用children定义嵌套路由
{path:'profile',component:Profile} // 没有/,以/开头的嵌套路径会被当作根路径
]
}
]
});
const vm=new Vue({
el:'#app',
router
});
</script>
7、命名视图
有时想同级展示多个视图,而不是嵌套展示。可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果router-view没有设置名字,默认为default。
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。使用components配置(带上s)。
<div id="app">
<router-view></router-view>
<router-view name="left"></router-view>
<router-view name="main"></router-view>
</div>
<script>
const router=new VueRouter({
routes:[
{path:'/',components:{
default:header,
left:leftBox,
main:mainBox
}
}
]
});
</script>
二、状态管理vuex
中文官网:https://vuex.vuejs.org/zh/ GitHub:https://github.com/vuejs/vuex
1、状态管理模式
Vuex是一个专为Vue.js应用程序开发的状态管理模式(公共数据管理工具)。它采用集中式存储管理应用的所有组件的状态(共享的数据),并以相应的规则保证状态以一种可预测的方式发生变化(整个程序中的任何组件直接获取或修改公共数据)。
// 组件
new Vue({
// state
data(){
return {
count:0
}
},
// view
template:`<div>{{count}}</div>`,
// actions
methods:{
increment(){
this.count++
}
}
})
状态自管理应用(组件)包含:state,驱动应用的数据源;view,以声明方式将state映射到视图;actions,响应在view上的用户输入导致的状态变化。但是,当应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏,如多个视图依赖于同一状态(传参繁琐)、来自不同视图的行为需要变更同一状态。
把组件的共享状态抽取出来,以一个全局单例模式管理,任何组件都能获取状态或者触发行为。
虽然Vuex可以帮助管理共享状态,但也附带了更多的概念和框架。如果不打算开发大型单页应用,使用Vuex可能是繁琐冗余的,一个简单的store模式就足够了。但如果需要构建一个中大型单页应用,更好地在组件外部管理状态则需要Vuex 。
2、安装与创建store
在Vue之后引入vuex会进行自动安装。
Vuex依赖Promise,如果浏览器并没有实现Promise(如IE),可以使用一个polyfill的库(es6-promise),可以通过CDN将其引入,之后window.Promise会自动可用。
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>
每一个Vuex应用的核心是store(仓库),基本上是一个容器,包含着应用中大部分的状态 (state)。Vuex使用单一状态树,用一个对象就包含了全部的应用层级状态,作为一个“唯一数据源 (SSOT)”而存在。每个应用仅包含一个store实例。
Vuex和单纯的全局对象不同,vuex的状态存储是响应式的,若store中的状态发生变化,相应的组件也会得到高效更新;改变store中的状态的唯一途径是显式地提交(commit)mutation,为了更明确地追踪到状态的变化。
创建一个store,仅提供一个初始state对象和一些mutation、getters。
在根实例中注册store选项,可将状态从根组件注入到每一个子组件中(需调用Vue.use(Vuex)),子组件通过this.$store访问。
const store=new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state){
state.count++
}
},
getters:{
optCount:state=>{
return 'count值是:'+state.count
}
}
})
const vm=new Vue({
el:"#app",
store // 将store挂载到vm实例,任何组件都可以使用store存储访问数据
})
console.log(store.state.count);
store.commit('increment')
console.log(store.getters.optCount);
3、核心概念
(1)state
store.state获取状态对象。由于store中的状态是响应式的,在组件中调用store中的状态仅需要在计算属性中返回即可,当然也可以用在函数中,等。
mapState辅助函数:用于一个组件获取多个状态,可省略store。单独构建的版本中辅助函数为Vuex.mapState。
import {mapState} from 'vuex'
export default{
computed:mapState({
count:state=>state.count,
// 简写为count:'count'
// 简写为'count' 计算属性名称与state的子节点名称相同时,给mapState传一个字符串即可
// 传字符串参数 'count' 等同于 `state => state.count`
// 为了使用this获取局部状态,必须使用常规函数,不能简写
countPlusLocalState(state){
return state.count+this.localCount
}
})
}
对象展开运算符:mapState函数返回的是一个对象,如果需要与局部计算属性混合使用,可使用对象展开运算符。
computed:{
localComputed(){},
...mapState({ // 使用对象展开运算符将此对象混入到外部对象中
// ...
})
}
(2)mutation
mutation非常类似于事件,每个mutation都有一个字符串的事件类型和一个回调函数。回调函数进行状态更改,接受state作为第一个参数。第二个参数可选,是mutation的载荷,应该是一个对象,可以包含多个字段且更易读。
store.commit('事件类型')方法触发状态变更。
store.commit('increment',{ // 方式1
amount:10
})
store.commit({ // 方式2
type:'increment',
amount:10
})
(3)getter
在store中定义getter,可以认为是store的计算属性,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
Getter接受state作为其第一个参数,可以接受其它getter作为第二个参数。
通过store.getters对象,可以以属性的形式访问这些值,作为Vue的响应式系统的一部分缓存其中。在对store里的数组进行查询时,也可以通过让getter返回一个函数实现给getter传参,通过方法访问时,每次都会去进行调用,而不会缓存结果。
getters:{
// ...
getTodoById:(state)=>(id)=>{
return state.todos.find(todo=>todo.id===id)
}
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
(4)action
(5)module
三、服务端渲染
待更新。。。