day06
路由的封装抽离
问题:所有的路由配置都堆在main.js中不太合适么?不好,会加大代码的复杂度
目标:将路由模块抽离出来。好处:差分模块,利于维护。
大致的做法就是,将路由相关的东西都提取到router文件下的index.js中。
以后的main.js文件中
router文件的index.js文件
// import Find from './views/Find'
// import My from './views/My'
// import Friend from './views/Friend'
// 在这里由于以后可能会移动文件夹,到时候需要回来改源代码,这时可以用绝对路径来适当的避免这种情况,而 @ 又可以简化绝对路径的写法import Find from '@/views/Find';
import My from '@/views/My';
import Friend from '@/views/Friend';// @ 代表的就是src目录 @/views 表示src目录下的views文件夹import VueRouter from 'vue-router';
import Vue from 'vue'; // 由于文件中没有Vue对象所以要导入Vue对象Vue.use(VueRouter); // VueRouter插件初始化const router = new VueRouter({// routes路由规则们// route一条路由规则 { path:路径,componeroutes: 组件名 }routes: [{ path: "/find" , component: Find },{ path: "/my " , component: My },{ path: '/friend ' , component: Friend }]
})// 导出 router
export default router;
main.js中
import Vue from "vue'
import App from "./App.vue'
// 导入封装的router文件
import router from "./router/index'vue.config-productionTip = falsenew Vue({render: h => h(App),router // 注入vue路由
}).$mount('#app');
一、声明式导航-导航链接
1.需求
实现导航高亮效果
如果使用a标签进行跳转的话,需要给当前跳转的导航加样式,同时要移除上一个a标签的样式,太麻烦!!!
2.解决方案
vue-router 提供了一个全局组件 router-link (取代 a 标签)
- 能跳转,配置 to 属性指定路径(必须) 。本质还是 a 标签 ,to 无需 #
- 能高亮,默认就会提供高亮类名,可以直接设置高亮样式
以前的写法:
如果是a标签,需要添加类名来让其高亮
学完后的写法:
如果是 router-link 会默认提供高亮类名
router-link 最后会直接渲染成 a 标签,并且会在a标签上添加一些特定的类名,那个a标签被选中了,特定的类名就会添加到被选中的a标签上。
语法: 发现音乐
<div><div class="footer_wrap"><router-link to="/find">发现音乐</router-link><router-link to="/my">我的音乐</router-link><router-link to="/friend">朋友</router-link></div><div class="top"><!-- 路由出口 → 匹配的组件所展示的位置 --><router-view></router-view></div></div>
<style>a.router-link-active {background-color: green;}
</style>
3.通过router-link自带的两个样式进行高亮
使用router-link跳转后,我们发现。当前点击的链接默认加了两个class的值 router-link-exact-active
和router-link-active
我们可以给任意一个class属性添加高亮样式即可实现功能
4.总结
- router-link是什么?
- router-link怎么用?
- router-link的好处是什么?
二、声明式导航-两个类名
当我们使用<router-link></router-link>
跳转时,自动给当前导航加了两个类名
1.router-link-active
模糊匹配(用的多)
to=“/my” 可以匹配 /my /my/a /my/b …
只要是以/my开头的路径 都可以和 to="/my"匹配到
2.router-link-exact-active
精确匹配
to=“/my” 仅可以匹配 /my 无法匹配 /my/a /my/b …
3.在地址栏中输入二级路由查看类名的添加
4.总结
- router-link 会自动给当前导航添加两个类名,有什么区别呢?
三、声明式导航-自定义类名(了解)
1.问题
router-link的两个高亮类名 太长了,我们希望能定制怎么办
2.解决方案
我们可以在创建路由对象时,额外配置两个配置项即可。 linkActiveClass
和linkExactActiveClass
const router = new VueRouter({routes: [...],linkActiveClass: "类名1",linkExactActiveClass: "类名2"
})
3.代码演示
// 创建了一个路由对象
const router = new VueRouter({routes: [...], linkActiveClass: 'active', // 配置模糊匹配的类名linkExactActiveClass: 'exact-active' // 配置精确匹配的类名
})
4.总结
如何自定义router-link的两个高亮类名
四、声明式导航-查询参数传参
1.目标
在跳转路由时,进行传参
比如:现在我们在搜索页点击了热门搜索链接,跳转到详情页,需要把点击的内容带到详情页,改怎么办呢?
2.跳转传参
我们可以通过两种方式,在跳转的时候把所需要的参数传到其他页面中
- 查询参数传参
- 动态路由传参
3.查询参数传参
-
如何传参?和以前的地址参数是差不多的。
-
如何接受参数
固定用法:$router.query.参数名
4.代码演示
App.vue
<template><div id="app"><div class="link"><router-link to="/home">首页</router-link><router-link to="/search">搜索页</router-link></div><router-view></router-view></div>
</template><script>
export default {};
</script><style scoped>
.link {height: 50px;line-height: 50px;background-color: #495150;display: flex;margin: -8px -8px 0 -8px;margin-bottom: 50px;
}
.link a {display: block;text-decoration: none;background-color: #ad2a26;width: 100px;text-align: center;margin-right: 5px;color: #fff;border-radius: 5px;
}
</style>
Home.vue
<template><div class="home"><div class="logo-box"></div><div class="search-box"><input type="text"><button>搜索一下</button></div><div class="hot-link">热门搜索:<router-link to="/search?word=黑马程序员">黑马程序员</router-link><router-link to="/search?word=前端培训">前端培训</router-link><router-link to="/search?word=如何成为前端大牛">如何成为前端大牛</router-link></div></div>
</template><script>
export default {name: 'FindMusic'
}
</script><style>
.logo-box {height: 150px;background: url('@/assets/logo.jpeg') no-repeat center;
}
.search-box {display: flex;justify-content: center;
}
.search-box input {width: 400px;height: 30px;line-height: 30px;border: 2px solid #c4c7ce;border-radius: 4px 0 0 4px;outline: none;
}
.search-box input:focus {border: 2px solid #ad2a26;
}
.search-box button {width: 100px;height: 36px;border: none;background-color: #ad2a26;color: #fff;position: relative;left: -2px;border-radius: 0 4px 4px 0;
}
.hot-link {width: 508px;height: 60px;line-height: 60px;margin: 0 auto;
}
.hot-link a {margin: 0 5px;
}
</style>
Search.vue
<template><div class="search"><p>搜索关键字: {{ $route.query.word }}</p><p>搜索结果: </p><ul><li>.............</li><li>.............</li><li>.............</li><li>.............</li></ul></div>
</template><script>
export default {name: 'MyFriend',created () { // 上面的参数有了,但是如何获取下面的li的内容呢// 就用created钩子函数,一旦dom元素加载完成就直接向后台获取参数// 在created中,获取路由参数,也可以用$route.query.参数名,但是必须在created函数中必须在前面加this,// this在created函数中不可以省略,但是在template标签中可以省略。console.log(this.$route.query.word);}
}
</script><style>
.search {width: 400px;height: 240px;padding: 0 20px;margin: 0 auto;border: 2px solid #c4c7ce;border-radius: 5px;
}
</style>
router/index.js
import Home from '@/views/Home'
import Search from '@/views/Search'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter) // VueRouter插件初始化// 创建了一个路由对象
const router = new VueRouter({routes: [{ path: '/home', component: Home },{ path: '/search', component: Search }]
})export default router
main.js
...
import router from './router/index'
...
new Vue({render: h => h(App),router
}).$mount('#app')
五、声明式导航-动态路由传参
1.动态路由传参方式
-
配置动态路由
动态路由后面的参数可以随便起名,但要有语义
const router = new VueRouter({routes: [...,{ path: '/search/:words', component: Search }] })
-
配置导航链接
to=“/path/参数值”
-
对应页面组件接受参数
$route.params.参数名
params后面的参数名要和动态路由配置的参数保持一致
上面的部分代码:
router/index.js
// 创建了一个路由对象
const router = new VueRouter({routes: [{ path: '/home', component: Home },{ path: '/search/:word', component: Search }// 配路由规则]
})
Home.vue
<template><div class="home"><div class="logo-box"></div><div class="search-box"><input type="text"><button>搜索一下</button></div><div class="hot-link">热门搜索:<router-link to="/search/黑马程序员">黑马程序员</router-link><router-link to="/search/前端培训">前端培训</router-link><router-link to="/search/如何成为前端大牛">如何成为前端大牛</router-link>// 配导航链接</div></div>
</template>
Search.vue
<template><div class="search">// 传递参数,接收参数<p>搜索关键字: {{ $route.parmas.word }}</p><p>搜索结果: </p><ul><li>.............</li><li>.............</li><li>.............</li><li>.............</li></ul></div>
</template><script>
export default {name: 'MyFriend',created () { console.log(this.$route.parmas.word);}
}
</script>
2.查询参数传参 VS 动态路由传参
-
查询参数传参 (比较适合传多个参数)
-
跳转:to=“/path?参数名=值&参数名2=值”
-
获取:$route.query.参数名
-
动态路由传参 (优雅简洁,传单个参数比较方便)
- 配置动态路由:path: “/path/:参数名”
- 跳转:to=“/path/参数值”
- 获取:$route.params.参数名
注意:动态路由也可以传多个参数,但一般只传一个
3.总结
声明式导航跳转时, 有几种方式传值给路由页面?
- 查询参数传参(多个参数)
- 动态路由传参(一个参数,优雅简洁)
六、动态路由参数的可选符(了解)
1.问题
配了路由 path:“/search/:words” 为什么按下面步骤操作,会未匹配到组件,显示空白?
2.原因
/search/:words 表示,必须要传参数。如果不传参数,也希望匹配,可以加个可选符"?"
const router = new VueRouter({routes: [...{ path: '/search/:words?', component: Search }]
})
七、Vue路由-重定向
1.问题
网页打开时, url 默认是 / 路径,未匹配到组件时,会出现空白。
2.解决方案
重定向 → 匹配 / 后, 强制跳转 /home 路径
重定向的效果可以通过,vue的钩子函数created和编程式导航的两种跳转方式来实现。
3.语法
{ path: 匹配路径, redirect: 重定向到的路径 },
比如:
{ path:'/' ,redirect:'/home' }
// 这里的 path 不一定是 '/' 也可以换成其他的路径,redirect 也可以换成其他的路径
4.代码演示
const router = new VueRouter({routes: [{ path: '/', redirect: '/home' }, // 最好是放在第一个{ path: '/Home', component: Home },{ path: '/Search/:word?', component: Search }...]
})
八、Vue路由-404
1.作用
当路径找不到匹配时,给个提示页面
2.位置
404的路由,虽然配置在任何一个位置都可以,但一般都配置在其他路由规则的最后面
3.语法
path: “*” (任意路径) – 前面不匹配就命中最后这个
import NotFind from '@/views/NotFind'const router = new VueRouter({routes: [...{ path: '*', component: NotFind } // 必须放在最后一个]
})
4.代码示例
NotFound.vue
<template><div><h1>404 Not Found</h1></div>
</template><script>
export default {}
</script><style>
</style>
router/index.js
...
import NotFound from '@/views/NotFound'
...// 创建了一个路由对象
const router = new VueRouter({routes: [...{ path: '*', component: NotFound }]
})export default router
九、Vue路由-模式设置
1.问题
路由的路径看起来不自然, 有#,能否切成真正路径形式?
- hash路由(默认) 例如: http://localhost:8080/#/home
- history路由(常用) 例如: http://localhost:8080/home (以后上线需要服务器端支持,服务端需要配置一些访问规则,如果不配置会出现页面空白的情况,开发环境中webpack给规避掉了history模式的问题)
hash路由是基于a标签毛链接跳转实现的。
history路由是基于新增的html5 history API 来实现的。
2.语法
const router = new VueRouter({mode:'histroy', //默认是hashroutes:[]
})
注意:一旦采用了 history 模式,地址栏就没有 # 了,这时是需要后台配置访问规则的。具体是什么访问规则,和后端说一下,后端自己会明白的。
十、编程式导航-两种路由跳转方式
1.问题
点击按钮跳转如何实现?
2.方案
编程式导航:用JS代码来进行跳转,直接 location.herf=“路径”。
但是,vue路由的本质就是一个单页,无法通过 JS 的 location.herf 来进行跳转。于是就有了路由专有的跳转方式。
3.语法
两种语法:
- path 路径跳转 (简易方便)
- name 命名路由跳转 (适合 path 路径长的场景)
4.path路径跳转语法
特点:简易方便
//简单写法
this.$router.push('路由路径');
// 注意这里是 router 而不是,route,要注意区分。
// router 指的是一个大的router对象。//完整写法 完整写法会在后面的传参的时候用到
this.$router.push({path: '路由路径'
})
5.代码演示 path跳转方式
Home.vue
<template>...<button @click="toSearch">搜索一下</button>...
</template><script>
export default {name: 'FindMusic',methods: {toSearch () {this.$router.push('/Search');// 下面这样也是可以的this.$router.push({path: '/Search',})}}
}
</script>
6.name命名路由跳转
特点:适合 path 路径长的场景
语法:
-
路由规则,必须事先给要跳转的配置项添加name属性,如果没有name配置项,是无法跳转到对应的配置项的。
... { name: '路由名', path: '/path/xxx', component: XXX }, ...
-
通过name来进行跳转
this.$router.push({name: '路由名' })
name跳转和path跳转互不冲突,可以一起使用。
7.代码演示通过name命名路由跳转
8.总结
编程式导航有几种跳转方式?
十一、编程式导航-path路径跳转传参
1.问题
点击搜索按钮,跳转需要把文本框中输入的内容传到下一个页面如何实现?
2.两种传参方式
1.查询参数
2.动态路由传参
3.传参
两种跳转方式,对于两种传参方式都支持:
① path 路径跳转传参
② name 命名路由跳转传参
4.path路径跳转传参(query传参)
//简单写法
this.$router.push('/路径?参数名1=参数值1&参数2=参数值2')
//完整写法
this.$router.push({path: '/路径',query: {参数名1: '参数值1',参数名2: '参数值2'}
})
接受参数的方式依然是:$route.query.参数名
Home.vue
<template>...<input v-model="inputValue" type="text"><button @click="toSearch">搜索一下</button>...
</template><script>
export default {name: 'FindMusic',data: {inputValue: '',key: ''},methods: {toSearch () {// this.$router.push(`/search?word=${this.inputValue}`);// 当参数比较多时不太好用,但是可以用完整写法,比如下面的写法this.$router.push({path: '/serach',query: {word: this.inputValue, // 注意:inputValue的获取要在前面加 this,否则无法获取。key: this.key}})}}
}
</script>
5.path路径跳转传参(动态路由传参)
//简单写法
this.$router.push('/路径/参数值')
//完整写法
this.$router.push({path: '/路径/参数值'
})
接受参数的方式依然是:$route.params.参数值
注意: path不能配合params使用,所以path的方式更加适合传递参数比较少时使用。
Home.vue
<script>
export default {name: 'FindMusic',data: {inputValue: ''},methods: {toSearch () {toSearch () {// this.$router.push(`/search/${this.inputValue}`);this.$router.push({path: `/search/${this.inputValue}`});}}}
}
</script>
十二、编程式导航-name命名路由传参
1.name 命名路由跳转传参 (query传参)
this.$router.push({name: '路由名字',query: {参数名1: '参数值1',参数名2: '参数值2'}
})
2.name 命名路由跳转传参 (动态路由传参)
this.$router.push({name: '路由名字',params: {参数名: '参数值',}
})
3.总结
编程式导航,如何跳转传参?
1.path路径跳转
-
query传参
this.$router.push('/路径?参数名1=参数值1&参数2=参数值2') this.$router.push({path: '/路径',query: {参数名1: '参数值1',参数名2: '参数值2'} })
-
动态路由传参
this.$router.push('/路径/参数值') this.$router.push({path: '/路径/参数值' })
2.name命名路由跳转
-
query传参
this.$router.push({name: '路由名字',query: {参数名1: '参数值1',参数名2: '参数值2'} })
-
动态路由传参 (需要配动态路由)
this.$router.push({name: '路由名字',params: {参数名: '参数值',} })
十三、面经基础版-案例效果分析
源码
1.面经效果演示
2.功能分析
- 通过演示效果发现,主要的功能页面有两个,一个是列表页,一个是详情页,并且在列表页点击时可以跳转到详情页
- 底部导航可以来回切换,并且切换时,只有上面的主题内容在动态渲染
3.实现思路分析:配置路由+功能实现
1.配置路由
- 首页和面经详情页,两个一级路由
- 首页内嵌套4个可切换的页面(嵌套二级路由)
2.实现功能
- 首页请求渲染
- 跳转传参 到 详情页,详情页动态渲染
- 组件缓存,性能优化
解释:App.vue中嵌套了两个路由,一个是首页,另一个时面经详情,当点击首页中的某个面经条例时,会直接跳转到条例对应的面经详情页面。首页中又包含了一些路由,当点击这些路由时,首页的面经条例会显示(跳转到)对应的条例页面。
十四、面经基础版-一级路由配置
1.把文档中准备的素材拷贝到项目中
2.针对router/index.js文件 进行一级路由配置
...
import Layout from '@/views/Layout.vue'
import ArticleDetail from '@/views/ArticleDetail.vue'
...const router = new VueRouter({routes: [{path: '/',component: Layout},{path: '/detail',component: ArticleDetail}]
})
十五、面经基础版-二级路由配置
二级路由也叫嵌套路由,当然也可以嵌套三级、四级…
1.使用场景
当在页面中点击链接跳转,只是部分内容切换时,我们可以使用嵌套路由
2.语法
- 在一级路由下,配置children属性即可
- 配置二级路由的出口
1.在一级路由下,配置children属性
注意:一级的路由path 需要加 /
二级路由的path不需要加 /
const router = new VueRouter({routes: [{path: '/',component: Layout,children:[//children中的配置项 跟一级路由中的配置项一模一样 {path:'xxxx',component:xxxx.vue},{path:'xxxx',component:xxxx.vue},]}]
})
技巧:二级路由应该配置到哪个一级路由下呢?
这些二级路由对应的组件渲染到哪个一级路由下,children就配置到哪个路由下边
2.配置二级路由的出口
注意: 配置了嵌套路由,一定配置对应的路由出口,否则不会渲染出对应的组件
Layout.vue
<template><div class="h5-wrapper"><div class="content"><router-view></router-view></div>....</div>
</template>
3.代码实现
router/index.js
...
import Article from '@/views/Article.vue'
import Collect from '@/views/Collect.vue'
import Like from '@/views/Like.vue'
import User from '@/views/User.vue'
...const router = new VueRouter({routes: [{path: '/',component: Layout,redirect: '/article',children:[{path:'/article',component:Article},{path:'/collect',component:Collect},{path:'/like',component:Like},{path:'/user',component:User}]},....]
})
Layout.vue
<template><div class="h5-wrapper"><div class="content"><!-- 内容部分 --><!-- 二级路由出口,匹配到的二级路由组件就会展示在这里 --><router-view></router-view></div><nav class="tabbar"><a href="#/article">面经</a><a href="#/collect">收藏</a><a href="#/like">喜欢</a><a href="#/user">我的</a></nav></div>
</template>
十六、面经基础版-二级导航高亮
1.实现思路
- 将a标签替换成 组件,配置to属性,不用加 #
- 结合高亮类名实现高亮效果 (推荐模糊匹配:router-link-active)
2.代码实现
Layout.vue
....<nav class="tabbar"><router-link to="/article">面经</router-link><router-link to="/collect">收藏</router-link><router-link to="/like">喜欢</router-link><router-link to="/user">我的</router-link></nav><style>a.router-link-active {color: orange;}
</style>
十七、面经基础版-首页请求渲染
1.步骤分析
1.安装axios
2.看接口文档,确认请求方式,请求地址,请求参数
3.created中发送请求,获取数据,存储到data中
4.页面动态渲染
2.代码实现
1.安装axios
yarn add axios
npm i axios
2.接口文档
请求地址: https://mock.boxuegu.com/mock/3083/articles
请求方式: get
3.created中发送请求,获取数据,存储到data中
data() {return {articelList: [],}},async created() {const { data: { result: { rows } }} = await axios.get('https://mock.boxuegu.com/mock/3083/articles')this.articelList = rows},
4.页面动态渲染
<template><div class="article-page"><div class="article-item" v-for="item in articelList" :key="item.id"><div class="head"><img :src="item.creatorAvatar" alt="" /><div class="con"><p class="title">{{ item.stem }}</p><p class="other">{{ item.creatorName }} | {{ item.createdAt }}</p></div></div><div class="body">{{item.content}}</div><div class="foot">点赞 {{item.likeCount}} | 浏览 {{item.views}}</div></div></div>
</template>
十八、面经基础版-查询参数传参
1.说明
跳转详情页需要把当前点击的文章id传给详情页,获取数据
- 查询参数传参 this.$router.push(‘/detail?参数1=参数值&参数2=参数值’)
- 动态路由传参 先改造路由 在传参 this.$router.push(‘/detail/参数值’)
2.查询参数传参实现
Article.vue
<template><div class="article-page"><div class="article-item" v-for="item in articelList" :key="item.id" @click="$router.push(`/detail?id=${item.id}`)">...</div></div>
</template>
ArticleDetail.vue
created(){console.log(this.$route.query.id)}
十九、面经基础版-动态路由传参
1.实现步骤
- 改造路由
- 动态传参
- 在详情页获取参数
2.代码实现
改造路由
router/index.js
...{path: '/detail/:id',component: ArticleDetail}
Article.vue
<div class="article-item" v-for="item in articelList" :key="item.id" @click="$router.push(`/detail/${item.id}`)">....</div>
ArticleDetail.vue
created(){console.log(this.$route.params.id)}
index.js
routes: [{path: '/',cpmponent: Layout,redirect: '/article', // 当到Layout的时候就直接重定向到指定的子路由中children: [{ path: '/article', component: Article },...]},...
]
3.额外优化功能点-点击回退跳转到上一页
ArticleDetail.vue
<template><div class="article-detail-page"><nav class="nav"><span class="back" @click="$router.back()"><</span> 面经详情</nav>....</div>
</template>
二十、面经基础版-详情页渲染
1.实现步骤分析
- 导入axios
- 查看接口文档
- 在created中发送请求
- 页面动态渲染
2.代码实现
接口文档
请求地址: https://mock.boxuegu.com/mock/3083/articles/:id请求方式: get
在created中发送请求
data() {return {articleDetail:{}}},async created() {const id = this.$route.params.idconst {data:{result}} = await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${id}`)this.articleDetail = result},
页面动态渲染
<template><!-- 由于数据的请求是需要时间的,这时候页面会出现暂时显示一些残缺的结构 --><!-- 可以通过v-if判断是否有文章的id值来决定是否渲染页面,具体操作如下 --><div class="article-detail-page" v-if="article.id"><nav class="nav"><span class="back" @click="$router.back()"><</span> 面经详情</nav><header class="header"><h1>{{articleDetail.stem}}</h1><p>{{articleDetail.createAt}} | {{articleDetail.views}} 浏览量 | {{articleDetail.likeCount}} 点赞数</p><p><img:src="articleDetail.creatorAvatar"alt=""/><span>{{articleDetail.creatorName}}</span></p></header><main class="body">{{articleDetail.content}}</main></div>
</template>
二十一、面经基础版-缓存组件
1.问题
从面经列表 点到 详情页,又点返回,数据重新加载了,并没有回到点进来之前滚动条的位置 → 希望回到原来的位置
2.原因
当路由被跳转后,原来所看到的组件就被销毁了(会执行组件内的beforeDestroy和destroyed生命周期钩子),重新返回后组件又被重新创建了(会执行组件内的beforeCreate,created,beforeMount,Mounted生命周期钩子),所以数据被加载了
3.解决方案
利用keep-alive把原来的组件给缓存下来
4.什么是keep-alive
keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件中。
优点:
在组件切换过程中把切换出去的组件保留在内存中,防止重复渲染DOM,
减少加载时间及性能消耗,提高用户体验性。
App.vue
<template><div class="h5-wrapper"><!-- 包裹了 keep-alive 一级路所匹配的组件都会被缓存这里的一级路由是 Layout 和 Detail 被缓存了 --><keep-alive><router-view></router-view></keep-alive></div>
</template>
直接这样写的小问题:
比如说从页面中点击一个文章1进去,这时,Layout 和 文章1的 Detail 会被缓存,点击返回时会回到原来的滚动条的位置,此时再点击一个文章3进去,由于文章1被缓存了,这样做会直接显示文章1而不是文章3。
这说明了并不是所有的组件都需要被缓存的,这可以通过keep-alive的属性来解决问题。
问题:
缓存了所有被切换的组件
5.keep-alive的三个属性
① include : 组件名数组,只有匹配的组件会被缓存,其他的组件默认不会被缓存。
② exclude : 组件名数组,任何匹配的组件都不会被缓存,其他的组件默认会被缓存。
③ max : 最多可以缓存多少组件实例
include和exclude并不可以同时用
App.vue
<template><div class="h5-wrapper"><keep-alive :include="['LayoutPage']"><router-view></router-view></keep-alive></div>
</template>
注意:include和exclude是组件名数组,也就是他们的值是一些组件名组成的数组,组件名就是每一个组件导出的name属性。如果没有配置name属性才会去找文件名作为组件名。通俗一点讲就是,name的优先级更高,没有name属性时才会去找文件名作为属性。
也可以这样写:App.vue
<template><div class="h5-wrapper"><keep-alive :include="keepArr"><router-view></router-view></keep-alive></div>
</template>
<script>
export default {name: 'h5-wrapper',data () {return {// 缓存组件的组件名数组keepArr: ['LayoutPage']}}
}
</script>
6.额外的两个生命周期钩子
keep-alive的使用会触发包裹的组件的两个生命周期函数
activated 当组件被激活(使用)的时候触发 → 进入这个页面的时候触发
deactivated 当组件不被使用的时候触发 → 离开这个页面的时候触发
注意是组件缓存之后!注意是组件缓存之后!注意是组件缓存之后!组件缓存后就不会执行组件的created, mounted, destroyed 等钩子了,缓存之前是会正常执行这些钩子函数的。
所以其提供了actived 和deactived钩子,帮我们实现业务需求。
Layout.vue
<script>
export default {name: 'LayoutPage',created () {console.log('created 组件被加载了');},mounted () {console.log('mounted dom渲染完了');},destroyed () {console.log('destroyed 组件被销毁了');},activated () {console.log('activated 组件被激活了');},deactivated () {console.log('deactivated 组件失活了');},
}
</script>
一开始加载页面时控制台显示:
created 组件被加载了
mounted dom渲染完了
activated 组件被激活了
说明已经创建,挂载并且缓存了起来。当点击一篇文章时控制台会继续出现:
deactivated 组件失活了
当点击返回时,控制台会继续出现:
activated 组件被激活了
7.总结
1.keep-alive是什么
vue的内置组件,包裹动态组件时,
2.keep-alive的优点
组件切换过程中把切换出去的组件保留在内存中(提升性能)
3.keep-alive的三个属性 (了解)
include :组件名数组,只有匹配的组件会被缓存
exclude :组件名数组,任何匹配的组件都不会被缓存
max︰最多可以缓存多少组件实例
4.keep-alive的使用会触发两个生命周期函数(了解)
activated当组件被激活(使用)的时候触发→进入页面触发
deactivated当组件不被使用的时候触发→离开页面触发
二十二、VueCli 自定义创建项目
1.安装脚手架 (已安装)
npm i @vue/cli -g
2.创建项目
vue create hm-exp-mobile
- 选项
Vue CLI v5.0.8
? Please pick a preset:Default ([Vue 3] babel, eslint)Default ([Vue 2] babel, eslint)
> Manually select features 选自定义
- 手动选择功能
- 选择vue的版本
3.x
> 2.x
- 是否使用history模式
- 选择css预处理
- 选择eslint的风格 (eslint 代码规范的检验工具,检验代码是否符合规范)
- 比如:const age = 18; => 报错!多加了分号!后面有工具,一保存,全部格式化成最规范的样子
- 选择校验的时机 (直接回车)
- 选择配置文件的生成方式 (直接回车)
- 是否保存预设,下次直接使用? => 不保存,输入 N
- 等待安装,项目初始化完成
- 启动项目
npm run serve
二十三、ESlint代码规范及手动修复
代码规范:一套写代码的约定规则。例如:赋值符号的左右是否需要空格?一句结束是否是要加;?…
没有规矩不成方圆
ESLint:是一个代码检查工具,用来检查你的代码是否符合指定的规则(你和你的团队可以自行约定一套规则)。在创建项目时,我们使用的是 JavaScript Standard Style 代码风格的规则。
1.JavaScript Standard Style 规范说明
建议把:https://standardjs.com/rules-zhcn.html 看一遍,然后在写的时候, 遇到错误就查询解决。
下面是这份规则中的一小部分:
- 字符串使用单引号 – 需要转义的地方除外
- 无分号 – 这没什么不好。不骗你!
- 关键字后加空格
if (condition) { ... }
- 函数名后加空格
function name (arg) { ... }
- 坚持使用全等
===
摒弃==
一但在需要检查null || undefined
时可以使用obj == null
- …
2.代码规范错误
如果你的代码不符合standard的要求,eslint会跳出来刀子嘴,豆腐心地提示你。
下面我们在main.js中随意做一些改动:添加一些空行,空格。
import Vue from 'vue'
import App from './App.vue'import './styles/index.less'
import router from './router'
Vue.config.productionTip = falsenew Vue ( {render: h => h(App),router
}).$mount('#app')
按下保存代码之后:
你将会看在控制台中输出如下错误:
eslint 是来帮助你的。心态要好,有错,就改。
3.手动修正
根据错误提示来一项一项手动修正。
如果你不认识命令行中的语法报错是什么意思,你可以根据错误代码(func-call-spacing, space-in-parens,…)去 ESLint 规则列表中查找其具体含义。
打开 ESLint 规则表,使用页面搜索(Ctrl + F)这个代码,查找对该规则的一个释义。
二十四、通过eslint插件来实现自动修正
- eslint会自动高亮错误显示
- 通过配置,eslint会自动帮助我们修复错误
- 如何安装
- 如何配置
// 当保存的时候,eslint自动帮我们修复错误
"editor.codeActionsOnSave": {"source.fixAll": true
},
// 保存代码,不自动格式化
"editor.formatOnSave": false
- 注意:eslint的配置文件必须在根目录下,这个插件才能才能生效。打开项目必须以根目录打开,一次打开一个项目
- 注意:使用了eslint校验之后,把vscode带的那些格式化工具全禁用了 Beatify
settings.json 参考
{"window.zoomLevel": 2,"workbench.iconTheme": "vscode-icons","editor.tabSize": 2,"emmet.triggerExpansionOnTab": true,// 当保存的时候,eslint自动帮我们修复错误"editor.codeActionsOnSave": {"source.fixAll": true},// 保存代码,不自动格式化"editor.formatOnSave": false
}