1. 路由进阶
1.1 路由的封装抽离
1.21 声明式导航 - 导航链接
1.22 声明式导航 - 两个类名
1.23 声明式导航 - 两个类名
import Find from '@/views/Find'
import My from '@/views/My'
import Friend from '@/views/Friend'import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter) // VueRouter插件初始化// 创建了一个路由对象
const router = new VueRouter({// routes 路由规则们// route 一条路由规则 { path: 路径, component: 组件 }routes: [{ path: '/find', component: Find },{ path: '/my', component: My },{ path: '/friend', component: Friend },],// link自定义高亮类名linkActiveClass: 'active', // 配置模糊匹配的类名linkExactActiveClass: 'exact-active' // 配置精确匹配的类名
})export default router
1.24 声明式导航 - 跳转传参
<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?key=黑马程序员">黑马程序员</router-link><router-link to="/search?key=前端培训">前端培训</router-link><router-link to="/search?key=如何成为前端大牛">如何成为前端大牛</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>
<template><div class="search"><p>搜索关键字: {{ $route.query.key }} </p><p>搜索结果: </p><ul><li>.............</li><li>.............</li><li>.............</li><li>.............</li></ul></div>
</template><script>
export default {name: 'MyFriend',created () {// 在created中,获取路由参数// this.$route.query.参数名 获取console.log(this.$route.query.key);}
}
</script><style>
.search {width: 400px;height: 240px;padding: 0 20px;margin: 0 auto;border: 2px solid #c4c7ce;border-radius: 5px;
}
</style>
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
import Vue from 'vue'
import App from './App.vue'
import router from './router/index'Vue.config.productionTip = falsenew Vue({render: h => h(App),router
}).$mount('#app')
<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>
<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><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>
<template><div class="search"><p>搜索关键字: {{ $route.params.words }} </p><p>搜索结果: </p><ul><li>.............</li><li>.............</li><li>.............</li><li>.............</li></ul></div>
</template><script>
export default {name: 'MyFriend',created () {// 在created中,获取路由参数// this.$route.query.参数名 获取查询参数// this.$route.params.参数名 获取动态路由参数console.log(this.$route.params.words);}
}
</script><style>
.search {width: 400px;height: 240px;padding: 0 20px;margin: 0 auto;border: 2px solid #c4c7ce;border-radius: 5px;
}
</style>
<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>
import Vue from 'vue'
import App from './App.vue'
import router from './router/index'Vue.config.productionTip = falsenew Vue({render: h => h(App),router
}).$mount('#app')
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/:words', component: Search }]
})export default router
1.25 动态路由参数可选符
1.31 Vue路由 - 重定向
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/:words?', component: Search }]
})export default router
1.32 Vue路由 - 404
import Home from '@/views/Home'
import Search from '@/views/Search'
import NotFound from '@/views/NotFound'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter) // VueRouter插件初始化// 创建了一个路由对象
const router = new VueRouter({routes: [{ path: '/', redirect: '/home' },{ path: '/home', component: Home },{ path: '/search/:words?', component: Search },{ path: '*', component: NotFound }]
})export default router
<template><div><h1>404 Not Found</h1></div>
</template><script>
export default {}
</script><style></style>
1.33Vue路由 - 模式设置
import Home from '@/views/Home'
import Search from '@/views/Search'
import NotFound from '@/views/NotFound'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter) // VueRouter插件初始化// 创建了一个路由对象
const router = new VueRouter({// 注意:一旦采用了 history 模式,地址栏就没有 #,需要后台配置访问规则mode: 'history',routes: [{ path: '/', redirect: '/home' },{ path: '/home', component: Home },{ name: 'search', path: '/search/:words?', component: Search },{ path: '*', component: NotFound }]
})export default router
1.41 编程式导航 - 基本跳转
1.42 编程式导航 - 路由传参
v
2. 面经基础版
2.1 案例效果:
路由配置
<template><div class="h5-wrapper"><div class="content"><!-- 二级路由出口,匹配到的二级路由组件就会展示 --><router-view></router-view></div><nav class="tabbar"><!-- 导航高亮1.将a标签换成router-link (to)2.结合高亮类名实现高亮效果 --><router-link to="#/router-linkrticle">面经</router-link><router-link to="#/collect">收藏</router-link><router-link to="#/like">喜欢</router-link><router-link to="#/user">我的</router-link></nav></div>
</template><script>
export default {name: "LayoutPage",
}
</script><style>
body {margin: 0;padding: 0;
}
</style>
<style lang="less" scoped>
.h5-wrapper {.content {margin-bottom: 51px;}.tabbar {position: fixed;left: 0;bottom: 0;width: 100%;height: 50px;line-height: 50px;text-align: center;display: flex;background: #fff;border-top: 1px solid #e4e4e4;a {flex: 1;text-decoration: none;font-size: 14px;color: #333;-webkit-tap-highlight-color: transparent;}}
}
</style>
import Vue from 'vue'
import VueRouter from "vue-router";
import Layout from '@/views/Layout'
import Article from '@/views/Article'
import Collect from '@/views/Collect'
import Like from '@/views/Like'
import User from '@/views/User'
import ArticleDetail from '@/views/ArticleDetail'
Vue.use(VueRouter)const router = new VueRouter({// /article 路径 -> Article组件routes: [{path:'/',component:Layout,//通过children配置项,可以配置嵌套子路由//1.在children配置项中,配规则//2.准备二级路由出口children: [{path:'/article',component:Article },{path:'/collect',component:Collect},{path:'/like',component:Like},{path:'/user',component:Uesr}]},{path:'/detail',component:ArticleDetail},{}]
})export default router
首先请求渲染
<template><div class="article-page"><divv-for="item in articles":key="item.id"@click="$router.push(`/detai/${item.id}`)"class="article-item" ><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><script>
//首页请求渲染
//1.安装axios
//2.看接口文档,确认请求方式,请求地址,请求参数// 请求地址: https://mock.boxuegu.com/mock/3083/articles// 请求方式: get
//3.creater中发送请求,获取数据,存起来
//4.页面的动态渲染//跳转详情页传参
//1.查询参数传参(更适合多个参数)//?参数=参数值 => this.$route.query.参数名
//2.动态路由传参(单个参数更优雅方便)// 改造路由 => /路径/参数 => this.$route.params.参数名//(1)访问/重定向到/article (redirect)//(2)返回上一页 $router.back()//请求地址:https://mock.boxuegu.com/mock/3083/articles/:id//请求方式:get
import axios from 'axios'
export default {name: 'ArticlePage',data () {return {articles:[]}},async created() {const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles')this.articles = res.data.result.rows}}
</script><style lang="less" scoped>
.article-page {background: #f5f5f5;
}
.article-item {margin-bottom: 10px;background: #fff;padding: 10px 15px;.head {display: flex;img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}.con {flex: 1;overflow: hidden;padding-left: 15px;p {margin: 0;line-height: 1.5;&.title {text-overflow: ellipsis;overflow: hidden;width: 100%;white-space: nowrap;}&.other {font-size: 10px;color: #999;}}}}.body {font-size: 14px;color: #666;line-height: 1.6;margin-top: 10px;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;}.foot {font-size: 12px;color: #999;margin-top: 10px;}
}
</style>
1.查询参数传参
<template><div class="article-detail-page"><nav class="nav"><span class="back"><</span> 面经详情</nav><header class="header"><h1>百度前端面经</h1><p>2022-01-20 | 315 浏览量 | 44 点赞数</p><p><imgsrc="http://teachoss.itheima.net/heimaQuestionMiniapp/%E5%AE%98%E6%96%B9%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F%402x.png"alt=""/><span>青春少年</span></p></header><main class="body">虽然百度这几年发展势头落后于AT, 甚至快被京东赶上了,毕竟瘦死的骆驼比马大,面试还是相当有难度和水准的, 一面.....</main></div>
</template><script>
// 请求地址: https://mock.boxuegu.com/mock/3083/articles/:id
// 请求方式: get
export default {name: "ArticleDetailPage",created () {console.log('this.$route.query.id');}}</script><style lang="less" scoped>
.article-detail-page {.nav {height: 44px;border-bottom: 1px solid #e4e4e4;line-height: 44px;text-align: center;.back {font-size: 18px;color: #666;position: absolute;left: 10px;top: 0;transform: scale(1, 1.5);}}.header {padding: 0 15px;p {color: #999;font-size: 12px;display: flex;align-items: center;}img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}}.body {padding: 0 15px;}
}
</style>
<template><div class="article-page"><divv-for="item in articles":key="item.id"@click="$router.push(`/detai?id=${item.id}`)"class="article-item" ><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><script>
//首页请求渲染
//1.安装axios
//2.看接口文档,确认请求方式,请求地址,请求参数// 请求地址: https://mock.boxuegu.com/mock/3083/articles// 请求方式: get
//3.creater中发送请求,获取数据,存起来
//4.页面的动态渲染//跳转详情页传参
//1.查询参数传参?参数=参数值 => this.$route.query.参数名
//2.动态路由传参 改造路由 => /路径/参数 => this.$route.params.参数名
import axios from 'axios'
export default {name: 'ArticlePage',data () {return {articles:[]}},async created() {const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles')this.articles = res.data.result.rows}}
</script><style lang="less" scoped>
.article-page {background: #f5f5f5;
}
.article-item {margin-bottom: 10px;background: #fff;padding: 10px 15px;.head {display: flex;img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}.con {flex: 1;overflow: hidden;padding-left: 15px;p {margin: 0;line-height: 1.5;&.title {text-overflow: ellipsis;overflow: hidden;width: 100%;white-space: nowrap;}&.other {font-size: 10px;color: #999;}}}}.body {font-size: 14px;color: #666;line-height: 1.6;margin-top: 10px;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;}.foot {font-size: 12px;color: #999;margin-top: 10px;}
}
</style>
2.动态传参
<template><div class="article-detail-page"><nav class="nav"><span @click="$router.back()" class="back"><</span> 面经详情</nav><header class="header"><h1>百度前端面经</h1><p>2022-01-20 | 315 浏览量 | 44 点赞数</p><p><imgsrc="http://teachoss.itheima.net/heimaQuestionMiniapp/%E5%AE%98%E6%96%B9%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F%402x.png"alt=""/><span>青春少年</span></p></header><main class="body">虽然百度这几年发展势头落后于AT, 甚至快被京东赶上了,毕竟瘦死的骆驼比马大,面试还是相当有难度和水准的, 一面.....</main></div>
</template><script>
// 请求地址: https://mock.boxuegu.com/mock/3083/articles/:id
// 请求方式: get
export default {name: "ArticleDetailPage",created () {console.log('this.$route.params.id');}}</script><style lang="less" scoped>
.article-detail-page {.nav {height: 44px;border-bottom: 1px solid #e4e4e4;line-height: 44px;text-align: center;.back {font-size: 18px;color: #666;position: absolute;left: 10px;top: 0;transform: scale(1, 1.5);}}.header {padding: 0 15px;p {color: #999;font-size: 12px;display: flex;align-items: center;}img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}}.body {padding: 0 15px;}
}
</style>
<template><div class="article-page"><divv-for="item in articles":key="item.id"@click="$router.push(`/detai/${item.id}`)"class="article-item" ><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><script>
//首页请求渲染
//1.安装axios
//2.看接口文档,确认请求方式,请求地址,请求参数// 请求地址: https://mock.boxuegu.com/mock/3083/articles// 请求方式: get
//3.creater中发送请求,获取数据,存起来
//4.页面的动态渲染//跳转详情页传参
//1.查询参数传参(更适合多个参数)//?参数=参数值 => this.$route.query.参数名
//2.动态路由传参(单个参数更优雅方便)// 改造路由 => /路径/参数 => this.$route.params.参数名//(1)访问/重定向到/article (redirect)//(2)返回上一页 $router.back()import axios from 'axios'
export default {name: 'ArticlePage',data () {return {articles:[]}},async created() {const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles')this.articles = res.data.result.rows}}
</script><style lang="less" scoped>
.article-page {background: #f5f5f5;
}
.article-item {margin-bottom: 10px;background: #fff;padding: 10px 15px;.head {display: flex;img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}.con {flex: 1;overflow: hidden;padding-left: 15px;p {margin: 0;line-height: 1.5;&.title {text-overflow: ellipsis;overflow: hidden;width: 100%;white-space: nowrap;}&.other {font-size: 10px;color: #999;}}}}.body {font-size: 14px;color: #666;line-height: 1.6;margin-top: 10px;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;}.foot {font-size: 12px;color: #999;margin-top: 10px;}
}
</style>
import Vue from 'vue'
import VueRouter from "vue-router";
import Layout from '@/views/Layout'
import Article from '@/views/Article'
import Collect from '@/views/Collect'
import Like from '@/views/Like'
import User from '@/views/User'
import ArticleDetail from '@/views/ArticleDetail'
Vue.use(VueRouter)const router = new VueRouter({// /article 路径 -> Article组件routes: [{path:'/',component:Layout,//重定向到/article (redirect)redirect:'/article',//通过children配置项,可以配置嵌套子路由//1.在children配置项中,配规则//2.准备二级路由出口children: [{path:'/article',component:Article },{path:'/collect',component:Collect},{path:'/like',component:Like},{path:'/user',component:Uesr}]},{//1.路由改造path:'/detail/:id',component:ArticleDetail},{}]
})export default router
详情页渲染
<template><div class="article-detail-page" v-if="article.id"><nav class="nav"><span @click="$router.back()" class="back"><</span> 面经详情</nav><header class="header"><h1>{{ article.stem }}</h1><p>{{ article.createdAt }} | {{ article.views }} 浏览量 | {{ article. likeCount}} 点赞数</p><p><img:src="article.creatorAvatar"alt=""/><span>{{ article.creatorName }}</span></p></header><main class="body">{{ article.content }}</main></div>
</template><script>
// 请求地址: https://mock.boxuegu.com/mock/3083/articles/:id
// 请求方式: get
import axios from 'axios'
export default {name: "ArticleDetailPage",data () {return {article:{}}},async created () {const id =this.$route.params.idconst {data}= await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${id}`)this.article = data.result}}</script><style lang="less" scoped>
.article-detail-page {.nav {height: 44px;border-bottom: 1px solid #e4e4e4;line-height: 44px;text-align: center;.back {font-size: 18px;color: #666;position: absolute;left: 10px;top: 0;transform: scale(1, 1.5);}}.header {padding: 0 15px;p {color: #999;font-size: 12px;display: flex;align-items: center;}img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}}.body {padding: 0 15px;}
}
</style>
返回上一页 $router.back()
2.2 组件缓存 keep-alive
<template><div class="h5-wrapper"><div class="content"><!-- 二级路由出口,匹配到的二级路由组件就会展示 --><router-view></router-view></div><nav class="tabbar"><!-- 导航高亮1.将a标签换成router-link (to)2.结合高亮类名实现高亮效果 --><router-link to="#/router-linkrticle">面经</router-link><router-link to="#/collect">收藏</router-link><router-link to="#/like">喜欢</router-link><router-link to="#/user">我的</router-link></nav></div>
</template><script>
export default {//组件名,如果没有配置name,才会找文件名作为组件名name: "LayoutPage",//组件缓存了,就不会执行组件的created,mounted,destroyed//所以提供了actived和deactivedcreated () {console.log('created 组件被加载了');},activated () {alert('你好,欢迎回到首页')console.log('activated 组件被激活了');},deactivated () {console.log('deactivated 组件被销毁了');},}
</script><style>
body {margin: 0;padding: 0;
}
</style>
<style lang="less" scoped>
.h5-wrapper {.content {margin-bottom: 51px;}.tabbar {position: fixed;left: 0;bottom: 0;width: 100%;height: 50px;line-height: 50px;text-align: center;display: flex;background: #fff;border-top: 1px solid #e4e4e4;a {flex: 1;text-decoration: none;font-size: 14px;color: #333;-webkit-tap-highlight-color: transparent;}}
}
</style>
<template><div class="h5-wrapper"><keep-alive :include="keepArr"><!-- 包裹了keep-alive一级路由匹配的组件都会被 缓存Layout组件 Detail组件,都会被缓存Layout组件 - 多两个生命周期的钩子-actived激活时,组件被看到时触发-deactived 失活时,离开页面组件看不见触发ArticleDatialPage组件(未被缓存)需求:只希望Layout被缓存,include配置:include="组件名数组"--><router-view></router-view></keep-alive></div>
</template><script>
export default {name: "h5-wrapper",data () {return {//缓存组件名的数组keepArr:['LayoutPage']}}
}
</script><style>
body {margin: 0;padding: 0;
}
</style>
<style lang="less" scoped>
.h5-wrapper {.content {margin-bottom: 51px;}.tabbar {position: fixed;left: 0;bottom: 0;width: 100%;height: 50px;line-height: 50px;text-align: center;display: flex;background: #fff;border-top: 1px solid #e4e4e4;a {flex: 1;text-decoration: none;font-size: 14px;color: #333;-webkit-tap-highlight-color: transparent;&.router-link-active {color: #fa0;}}}
}
</style>
2.3 自定义创建项目
2.4 ESlint 代码规范
JavaScript Standard Style
2.5 代码规范错误
规则参考 - ESLint - 插件化的 JavaScript 代码检查工具