vue-app
路由
后端路由
前端写不同的路径后端返回不同的html文件,一般用于多页应用
前端路由
后端返回的只有index.html这一个文件,也米娜跳转通过组件之间的切换实现,这个时候我们就需要前端路由了,也就是前端来分配每一个组件所对应的路径,这种用于SPA
vue全家桶:vue-cli vue-router vuex
vue-router
基本配置步骤
- 安装vue-router
- 创建router目录,里面创建index.js文件
- 在index.js里配置路由
- 引入Vue、vue-router
- vue.use(VueRouter)
- new一个router的实例,在里面配置路由
- 这里一般会把路由的配置放入另外一个routes.js里
- 在routes.js里引入需要配置路由的组件
- 将实例导出
- 在main.js里引入router实例,挂载到vue实例上,这样整个项目里都可以应用上这个router
- 在需要的地方写router-link组件,to属性写需要跳转的组建的path
- 写router-view,将来组件渲染的位置,router-view本身是不渲染的
嵌套路由
// Man组件和Woman组件复用性不高,分别写的两个不同的组件
const routes = [
{
path: '/cloth',
name: 'cloth',
component: Cloth,
children: [
{
path: 'man',
name: 'man',
component: Man
},
{
path: 'woman',
name: 'woman',
component: Woman
}
]
}
]
动态路由
const routes = [
{
path: '/cloth',
name: 'cloth',
component: Cloth,
children: [
{
// path是一个动态的,:cateName 接收跳转过来的时候的params
// 比如 /cloth/man 路由里的params.cateName === 'man'
path: ':cateName',
name: 'category',
component: Category
// props: true // 如果这里写true的话再Category组件里可以通过props来接收cateName
}
]
}
]
router-link 传参
<router-link
:to="{ name: 'category', params: { cateName: 'man', type: 1 } }"
>男装</router-link>
<router-link :to="{ path: '/cloth/woman', query: { id: 4 } }">女装</router-link>
<router-link to="/cloth/kids">童装</router-link>
男装传过去的param.type就是隐式传参
女装query就是url后面?的参数
童装就是最基本的写法
router-view
在当前组件里有router-link跳转的组件渲染到router-view里
一般来讲一个组件里有一个router-view,但是如果有多个组件要渲染,那就给router-view起名字
命名视图
<!-- Home.vue -->
<div class="app-main">
<router-view />
</div>
<router-view name='footer' />
路由里需要这样配置
{
path: '/home',
name: 'home',
components: {
default: Home,
footer: MyFooter
}
}
重定向和别名
一般重定向和别名不会同时用
const routes = [
{
path: '/',
// 重定向:如果url是/就会自动跳转到/home
redirect: '/home',
},
{
path: '/home',
name: 'home',
components: {
default: Home,
footer: MyFooter
},
// alias别名, / 以及 /home都会渲染Home这个组件
// alias: '/'
},
]
路由元信息
在配置路由的时候可以使用meta配置元信息,就是一些自定义字段
{
path: '/home',
name: 'home',
components: {
default: Home,
footer: MyFooter
},
meta: {
requiresAuth: false
}
}
编程式导航
this.$router.back() // 回到上一级
this.$router.push('/login') // 跳转路由
this.$router.push({
name: 'login',
params: { type: 'admin' },
query: { id: 12 }
})
异步组件 - 分包 - 路由懒加载
// 引入组件:异步组件,按需引入
// 注释语法,写相同的webpackChunkName的组件会打包到同一个js文件里
// Home组件和Todos组件的代码会打包到first.js里
// import方法返回的是一个promise
const Home = () => import(/* webpackChunkName: "first" */ '@/views/Home')
const Cloth = () => import(/* webpackChunkName: "cloth" */ '@/views/Cloth')
const Todos = () => import(/* webpackChunkName: "first" */ '@/views/Todos')
const Login = () => import(/* webpackChunkName: "cloth" */ '@/views/Login')
history历史模式
const router = new VueRouter({
mode: 'history',
routes
})
导航守卫
// 全局导航守卫
// 模拟登录状态,以后我们可以获取这个数据
const isLogin = true
router.beforeEach((to, from, next) => {
// 全局的守卫:任意一个路由发生改变就会进入这个守卫
// console.log({ to, from })
if (to.meta.requiresAuth) {
// 当前组件需要登录验证
if (isLogin) {
next()
} else {
// 没有登录就跳转到登录页
next('/login')
}
} else {
// 只有调用了next才会正常跳转
next()
}
})
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
console.log({ to, from })
this.cateName = to.params.cateName
// 根据不同的cateName请求不同数据
this.fetchData()
next()
},
// watch: {
// 如果路由有变化,会再次执行该方法
// 如果不用导航守卫的话监听$route也可以实现功能,再次调用fetchData
// '$route': 'fetchData'
// },
methods: {
fetchData () {
}
}
vuex用法
-
创建一个store/index.js
在这里引入state、mutations、getters、actions创建Store实例
-
把state、mutations、getters、actions分别都分离出去写
-
在main.js里引入store,挂载vue实例里,任何一个子组件都可以使用this.$store访问store实例
-
在组建里通过computed去使用state和getters
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex' export default { computed: { ...mapState(['count']), ...mapGetters(['restCount']) } }
就可以在组件里非常方便的使用 count 和restCount了
-
修改state
-
同步修改
methods: { ...mapMutations(['increment']) }
当我们使用mapMutations之后 methods字段里就有一个increment方法,这个方法里的内容就是commit一个increment 的mutation
<button @click="increment()">Add</button> <button @click="increment({ num: 2 })">Add2</button>
无论是否需要payload,@click=“increment()” 方法都加上小括号,这样没有payload mutation里接受的就是undefined,这样逻辑更容易处理
-
异步修改
methods: { ...mapActions(['asyncIncrement']) }
<button @click="asyncIncrement()">Async Add</button> <button @click="asyncIncrement({ num: 2})">Async Add2</button>
action需要修改一下
export default { // action负责异步提价mutation,不负责修改数据 asyncIncrement (context, payload) { // action不负责payload的任何逻辑,只负责从调用的位置接收payload继续传给mutation setTimeout(() => { context.commit('increment', payload) }, 1000) } }
-