Vue 进阶
-
动态路由 + 路由传参 + 路由接参
- 案例: 移动端常见的: 分类 -》 列表 -》 详情 -》 购物车
-
引入组件库
-
组件库就是可以快速帮助我们实现样式布局和基本逻辑
-
组件库 vs ui库
- 组件库指的是有组件构成的类库
- ui库更多偏向的的是样式: sui
-
类型
说明:Vue的组件库很多,我这边列举的是比较流行的
-
pc端 【 后台管理系统 】
-
element-ui 饿了吗前端开发团队完成
-
iview
-
-
移动端
-
Mint-ui
-
Vant
-
-
-
组件库安装
-
安装方式
-
全局引入: 将组件库中所有组件都引入项目,这样会增大项目体积
-
yarn add element-ui -D
-
在main.js中引入: import ElmentUI from ‘element-ui’
-
在main.js中使用Vue.use注册插件
- Vue.use( ElementUI )
-
-
按需引入: 只将我们需要的组件引入进来
- yarn add element-ui
- yarn add babel-plugin-component -D 帮助我们做按需引入的第三方模块
-
-
-
注意: 项目配置文件修改了,我们必须重启项目
测试组件库是否引入成功
多试几个组件库,多用几个
-
Vue项目配置反向代理,实现跨域
-
Vue cli3 webpack配置放在node_modules 中,也就是说我们不能直接更改,Vue提供了一个叫做vue.config.js的文件,没来作为webpack的覆盖配置文件,也可以说是vue项目的配置文件
-
vue.config.js 文件是放在项目 根目录 中
-
vue.config.js 文件是webpack配置文件,webpack底层就是node.js
- 使用的是common.js规范
module.exports = { devServer: { proxy: { // 一个键值就是一个反向代理的配置 '/index.php': { target: 'http://www.qinqin.net',//目标源指的就是你要跨域的目标 changeOrigin: true, // 修改目标源为我们当前源 } } } }
-
修改配置文件,项目要重启 【 特别注意 】
-
-
案例演示
-
动态路由
-
在vue项目中,使用vue-router如果进行不传递参数的路由模式,则称为静态路由;如果能够传递参数,对应的路由数量是不确定的,此时的路由称为动态路由。动态路由,是以冒号为开头的(😃
-
举例:
- localhost:3000/detail/001?a=1&b=2
- localhost:3000/detail/002?a=2&b=3
- detail
{ path: '/list/:id', //用于url携带id 和 查找字符串 component: List, name: 'list' },
-
-
路由传参
-
在router-link组件的to属性上进行–声明式
<router-link :to = "{ name: 'list', params: { id: ele.api_cid }, query: { cid: ele.api_cid } }" > <img :src = " ele.img " alt=""> <span> {{ ele.name }} </span> </router-link>
-
通过编程式导航来完成
- push
- this.$router.push(’/home’)
- this.$router.push({name,params,query})
- push可以将我们的操作存放到浏览器的历史记录
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: '123' }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:
const userId = '123' router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 这里的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user
-
replace
- this.$router.replace(’/home’)
- this.$router.replace({name,params,query})
- replace没有将我们的操作存放到浏览器的历史记录, 效果为返回了二级
-
push/replace的参数就是to属性的参数
-
router(n)
- 这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似
methods: { goBack () { this.$router.go( -1 ) } }, // 在浏览器记录中前进一步,等同于 history.forward() router.go(1) // 后退一步记录,等同于 history.back() router.go(-1) // 前进 3 步记录 router.go(3) // 如果 history 记录不够用,那就默默地失败呗 router.go(-100) router.go(100)
- push
-
-
路由接参
-
通过 this.$route就可以将路由路径中的数据接收到,这个就是路由接参
-
一般用来请求数据时候的参数 类似于 购物车的 sid。。。。。。。
params: { r: 'class/cyajaxsub', page: 1, cid: this.$route.query.cid, //通过this.$route px: 't', cac_id: '' }
-
-
动态路由组件
- 当url发生改变时,对应的组件是不变的,也就是共用了同一个组件,那么这就是动态路由组件
-
编程式导航
-
push
-
replace
-
push vs replace
- replace 不会将我们的页面跳转放入历史记录,效果是返回2层
- push 会将我们的页面跳转放入历史记录,效果返回一层
-
-
如果我们给组件身上添加原生事件,那么我们需要加一个修饰符 native
<el-button type="primary" @click.native = "goLogin"> 登录 </el-button>
路由的导航守卫
阿里p7要求: 路由导航守卫 、 路由鉴权
-
共有三个类型
-
to表示目标路径 - 我想进哪里
-
from表示当前路径 - 我现在所处的路径
-
next 表示 from 到 to的连接 ,它可以控制是否允许进入
- next() 表示允许通过 默认实参为true
- next () == next(true)
- next (true) 表示可以进入
- next (false) 表示不允许进入
- 如果 不写next 表示不允许进入
-
业务:当我们登陆了之后,我们前端要将后端给的token值存储起来,然后我们通过判断token是否存在,来进入项目
router.beforeEach(( to,from,next ) => { const token = localStorage.getItem( 'token' ) // 如果token不存在,那么我们自动跳转登录页面,然后让用户登录,来获得token值 if ( to.path == '/home') { next() } if ( to.path == '/category' ) { next() } if ( !token ) { // next( 路由路径 ) 可以跳转某一个路由 /* 以下这么些会出现一个问题就是死循环 */ // console.log( 1 ) // next('/mine/login') // next() /* 所以要想不出现死循环,我们要加判断条件 思考: 需要打破这个死循环的条件 这样,用户进入哪一个页面可以由我们来控制 */ switch ( to.path ) { case '/home': next('/mine/login') next() break; case '/category': next('/mine/login') next() break; case '/shopcar': next('/mine/login') next() break; default: break; } } }
-
-
路由独享守卫
-
组件内守卫
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }
-
beforeRouteEnter
前置守卫- 拦截 表示进入组件之前
- 数据预载 【 给组件提前获得数据】
- 问题:我们想把获得的数据提前给到组件,但是我们在这个钩子中无法获得组件,this也没有
- 示例如下:
data () { return { category: { //注意这里写两层 data: null } } }, beforeRouteEnter ( to,from,next ) { // 表示进入组件前 console.log( this ) // 没有this axios.get('/mock/shopcar.json') .then( res => { console.log( 'res',res ) // 问题:我们想把获得的数据提前给到组件,但是我们在这个钩子中无法获得组件,this也没有 // 解决 next( vm => { // vm就是当前组件 console.log( 'vm',vm ) // vm.name = "yyb" 这么加的话是无法成功的 // 因为vue中响应式数据要求在data选项中定义 vm.$set( vm.category, 'data', res.data )//这样加我们的数据合并到data选项中 // vm.$set / Vue.$set底层是Object.assign 也就是对象合并 next() }) }) .catch( err => console.log( err )) },
-
beforRouteUpdate
更新守卫- 路由改变 但是组件复用的 情况下就会调用这个钩子
- 例如:
- 对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。可以访问组件实例
this
- 对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。可以访问组件实例
-
beforRouteLeave
后置守卫- 也是拦截
- 在用户离开路由前触发
- 这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过
next(false)
来取消。
beforeRouteLeave ( to,from,next ) { // 也是拦截 // this可以拿到 if ( this.username || this.password || this.email || this.phone ) { if ( confirm( '您确定要离开吗' ) ) { next() } else { next( false ) } } else { next() } },
-
-
-
如何处理路由拦截,也就是我们被卡在登录页面或是其他页面
- 想办法得到token
- 后台接口文档中找登录的接口,然后自己写个ajax发送一次请求,然后将token保存在cookie
- 如果token拿不到,我们就先 注释 掉人家的拦截【 导航守卫 】,然后完成自己的任务
- 想办法得到token
-
数据请求拿不到怎么办?
- 根据接口文档,对应的返回值的字段 mock 数据 , 进行数据请求,然后数据渲染
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 用创建好的实例调用
beforeRouteEnter
守卫中传给next
的回调函数。
路由懒加载
默认分块
-
结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载。
- 结合这两者,这就是如何定义一个能够被 Webpack 自动代码分割的异步组件。
const Foo = () => import('./Foo.vue')
把组件按组分块
有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
过渡动效
-
<router-view>
是基本的动态组件,所以我们可以用<transition>
组件给它添加一些过渡效果:<transition> <router-view></router-view> </transition>
<transition mode="in-out" //先进后出 mode="out-in" //先出后进 enter-active-class="animated lightSpeedIn" //开始的动画 leave-active-class="animated lightSpeedOut" //离开的动画 > <router-view></router-view> </transition>
-
也可以给单个路由设置过度动画效果
- 上面的用法会给所有路由设置一样的过渡效果,如果你想让每个路由组件有各自的过渡效果,可以在各路由组件内使用
<transition>
并设置不同的 name。
const Foo = { template: ` <transition name="slide"> <div class="foo">...</div> </transition> ` } const Bar = { template: ` <transition name="fade"> <div class="bar">...</div> </transition> ` }
- 上面的用法会给所有路由设置一样的过渡效果,如果你想让每个路由组件有各自的过渡效果,可以在各路由组件内使用
-
普通标签也可以使用过度动画效果
<div id="example-1"> <button @click="show = !show"> Toggle render </button> <transition name="slide-fade"> <p v-if="show">hello</p> </transition> </div>
-
普通标签也可以使用过度动画效果
<div id="example-1"> <button @click="show = !show"> Toggle render </button> <transition name="slide-fade"> <p v-if="show">hello</p> </transition> </div>
Vue 路径别名
module.exports = {
chainWebpack: config => {
config.resolve.alias
// 需要重启 IDE
.set('assets', resolve('src/assets'))
.set('components', resolve('src/components'))
// 这里只写了两个个,你可以自己再加,按这种格式.set('', resolve(''))
}
}