一、路由(续)
1、router-link:用于取代a标签
功能:
1、能跳转:配置to属性指定路径(必须),本质上还是a标签(使用to时无需#)
2、默认就会提供高亮类名,可以直接设置高亮样式
语法:
<router-link to="/find"></router-link>
作用:
会为需要高亮的位置添加router-link-exact和a.router-link-exact-active两个类
router-link-exact:用于模糊匹配
如:to='/my'可以匹配到/my /my/a /my/b
router-link-exact-active:用于精确匹配
如:to='/my'仅可以匹配/my
2、自定义匹配类名
1、用于自定义模糊匹配和精确匹配的类名
const router = new VueRouter({
routes:[...],
linkActiveClass:"mohu",
//设置模糊类名
linkExactActiveClass:"jingque",
//设置精确类名
})
3、路由的封装抽离
1、目标:将路由模块从main.js中抽离出来。
好处:拆分模块,利于维护
2、步骤:
1、新建router -> index.js
2、导入到index.js
如:
import Find from '@/views/Find'
import My from '@/views/My'
import Friend from '@/views/Friend'
//@是一个绝对路径的标识,表示src
import VueRouter from 'vue-router'
import Vue from 'vue'
Vue.use(VueRouter)
const router = new VueRouter({
routes:[
{ path:'/find', component:Find},
{ path:'/My', component:My},
{ path:'/friend',component:Friend}
],
linkActiveClass:"mohu",
linkExactActiveClass:"jingque",
})
export default router
//导出router配置
...
import router from './router/index'
//在main中导入
4、声明式导航 - 跳转传参
目标:在跳转路由时,进行传参
1、查询参数传参
(1)语法:
to="/path?参数名=值"
(2)在对应页面中接受传递过来的值
$route.query.参数名
2、动态路由传参
(1)配置动态路由
routes:[
...,
{
path:'/search/:words',
//注:冒号不可省略,表示动态路由
component:Search
}
]
(2)配置导航链接
to="/path/参数值"
(3)对应页面组件接收传递过来的值
$route.params.参数名
如:
//index.js
const router = new VueRouter({
routes: [
{ path: '/home', component: Home },
{ path: '/search/:words', component: Search }
]
})
//home.vue
<div class="hot-link">
热门搜索:
<router-link to="/search/黑马程序员">黑马程序员</router-link>
<router-link to="/search/前端培训">前端培训</router-link>
<router-link to="/search/如何成为前端大牛">如何成为前端大牛</router-link>
</div>
//search.vue
<p>搜索关键字: {{$route.params.words}} </p>
(4)可选符:
/search/:words表示,必须要传参数,如果希望可匹配也可不匹配,可以加上可选符"?"
/search/:words?
5、Vue路由 - 重定向
问题:网页打开,url默认是/路径,未匹配到组件时,会出现空白
说明:重定向 - 匹配path后,强制跳转path路径
语法:{path:匹配路径,redirect="重定向到的路径"}
6、Vue路由 - 404
作用:路径无法匹配时,给出的提示页面
位置:配置到路由最后
语法:path:"*"(任意路径) - 前面的都不匹配就命中最后一个
如:
{ path: '*', component:NotFound}
7、Vue路由 - 模式设置
问题:路由的路径默认带有#,能否切换成真正路由形式
· hash路由(默认)
· history路由(常见)
如:
const router = new VueRouter({
routes: [
...
],
mode:"history"
//设置路由模式
})
8、编程式导航 - 基本跳转
问题:点击按钮如何跳转
编程式导航:用JS代码来进行跳转
1、path路径跳转(简易方便)
this.$router.push('路由路径')
this.$router.push({
path:'路由路径'
})
2、name命名路由跳转(需要先给路由取个名字,适合path路径长的场景)
如:
{ name:'search',path: '/search/:words?', component: Search }
...
this.$router.push({
name:'search'
})
9、编程式导航 -路由传参
问题:点击搜索按钮,跳转需要传参如何实现
两种传参方式:查询参数 + 动态路由传参
1、path路径跳转传参(query传参)
this.$router.push({
path:路径,
query:{
参数名1:参数1
参数名2:参数2
}
2、path路径跳转传参(动态路由传参)
path:`/search/参数`
1、name命名路由跳转传参(query传参)
this.$router.push({
name:'路由名字'
query:{
参数名1:参数1
参数名2:参数2
}
2、name命名路由跳转传参(动态路由传参)
this.$router.push({
name:'路由名字',
params:{
参数名1:参数1,
参数名2:参数2,
//注:需要和动态路由中指定的值相同
}
})
二、面经(基础版)
案例分析:配路由 + 实现功能
1、配置路由:
(1)首页和面经详情,两个一级路由
(2)首页内嵌四个可切换页面(嵌套二级路由)
2、实现功能:
(1)首页请求渲染
(2)跳转传参到详情页,详情页渲染
(3)组件缓存,优化性能
1、二级组件:
二级组件和一级组件是包含而非并列的关系,所以在编写时需要以chiren包含的方式
routes: [
{
path:'/',
component:Layout,
//通过children可以配置嵌套子路由
// 在children配置项中,配规则
// 准备二级路由出口
children:[
{
path:'/article',
component:article
},
...
]
},
并且需要给一个二级路由出口
//Layout
<div class="h5-wrapper">
<div class="content">
内容
<!-- 二级路由出口,匹配到的耳机路由组件 -->
<router-view></router-view>
</div>
</div>
3、组件缓存:
(1)问题:切换页面时,页面会重新加载 - 希望恢复到原来的位置
(2)解决:利用keep-alive将组件缓存下来
1、keep-alive
作用:当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
优点:减少加载时间及性能消耗,提高用户体验性
语法:
<keep-alive>
<router-view></router-view>
//<router-view>中的组件都会被缓存
</keep-alive>
*问题:全部都被缓存了,包括一些可能不需要的项目*
2、配置项
(1)include : 组件名数组,只有匹配的组件会被缓存
(2)exclude :组件名数组,任何匹配的组件都不会被缓存
(3)max :最多可以缓存多少组件实例()
注:匹配时会先匹配name,如果没有name,才会匹配文件
3、注:
组件被包裹,实际上就是多了两个生命周期
- activated 激活时,组件被看到时触发
- deactived 失活时,离开页面组件看不见时触发
4、代码:
index.js
import Vue from 'vue'
import VueRouter from "vue-router";
import Layout from "@/views/Layout";
import ArticleDetail from '@/views/ArticleDetail';
import article from '@/views/Article';
import collect from '@/views/Collect';
import like from '@/views/Like';
import User from '@/views/User';
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{
path:'/',
component:Layout,
redirect:'/article',
//当路径是/时,强制跳转到'/article'
children:[
{
//通过children可以配置嵌套子路由
// 在children配置项中,配规则
// 准备二级路由出口
path:'/article',
component:article
},
{
path:'/collect',
component:collect
},
{
path:'/like',
component:like,
},
{
path:'/User',
component:User
}
]
},
{
path:'/detail/:id',
component:ArticleDetail
},
],
mode:'history',
//设置路径模式
linkActiveClass:"mohu",
linkExactActiveClass:"jingque",
//修改模糊匹配和精确匹配的命名
})
export default router
//将router配置导出
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
//导入
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router,
}).$mount('#app')
App.vue
<template>
<div class="h5-wrapper">
<keep-alive :include=keepArr>
//将keepArr页面缓存,以获得更好的使用感
<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>
ArticleDetail.vue
<template>
<div class="article-detail-page" v-if="article.id">
//如果id存在,才加载页面
<nav class="nav"><span class="back" @click="$router.back()"><</span> 面经详情</nav>
//router.back()可以返回上一页
<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>
import axios from 'axios'
// 请求地址: https://mock.boxuegu.com/mock/3083/articles/:id
// 请求方式: get
export default {
name: "ArticleDetailPage",
data() {
return {
article:{}
}
},
async created(){
const ans = await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${this.$route.params.id}`)
this.article = ans.data.result
console.log(this.article);
},
methods:{
}
}
</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>
Article.vue
<template>
<div class="article-page">
<div
v-for="(item) in articles" :key="item.id"
@click="$router.push(`/detail/${item.id}`)"
class="article-item"
>
<div class="head">
<img :src="item.creatorAvatar" :alt="item.subjectName" />
<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.view }}</div>
</div>
</div>
</template>
<script>
// 请求地址: https://mock.boxuegu.com/mock/3083/articles
// 请求方式: get
import axios from 'axios'
export default {
name: 'ArticlePage',
async created(){
const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles')
console.log(res.data.result.rows);
this.articles = res.data.result.rows
},
data () {
return {
articles:[]
}
}
}
</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>
Layout.vue
<template>
<div class="h5-wrapper">
<div class="content">
<!-- 二级路由出口,匹配到的二级路由组件 -->
<router-view></router-view>
</div>
<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>
</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;
}
}
.tabbar .mohu{
background-color: #413843;
color:#e6f32e
}
a:hover{
background-color: #cfcdcd;
}
}
</style>
User.vue
<template>
<div>User</div>
</template>
<script>
export default {
name: 'UserPage'
}
</script>
Like.vue
<template>
<div>Like</div>
</template>
<script>
export default {
name: 'LikePage'
}
</script>
Collect.vue
<template>
<div>Collect</div>
</template>
<script>
export default {
name: 'CollectPage'
}
</script>
三、ESlint代码规范
代码规范:一套写代码的约定规则。
如:“赋值符号的左右是否需要空格”“一句结束是否要加;”...
JavaScript Standard Style规范说明:
https://standardjs.com/rules-zhcn.html
如:
字符串使用单引号
无分号
关键字后加空格
函数名后加空格
坚持使用全等
...
1、目标:学会解决代码规范错误
1、手动修正
根据错误提示来一项一项修改纠正
如果你不认识命令行中的语法报错是什么意思,可以根据错误代码去[ESLint规则表]中查找其具体含义
2、自动修正
基于vscode插件ESLint高亮错误,并通过配置自动帮助我们修复错误
配置:
在设置(左下角齿轮) - 打开设置(右上角)中输入
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"editor.formatOnSave": false
标签:Vue,import,Day5,path,router,article,跳转,日记,路由
From: https://blog.csdn.net/Lin_Zhong_/article/details/136702204