Vue2-面经基础版-案例

Vue2-面经基础版-案例【黑马程序员】

一、案例效果分析

案例效果

在这里插入图片描述

底下四个导航切换对应的四个页面

第一个渲染出来的列表中点击跳转详情

分析:配路由+实现功能

  1. 配路由:
    • 【首页】和【面经详情】,这两个一级路由(页面要么渲染首页,要么渲染详情页,并且二者可以通过一定方式来回跳转)
    • 【首页】内嵌四个可切换页面嵌套*二级路由*)
  2. 实现功能:
    • 【首页】请求渲染
    • 跳转传参到详情页(不同的文章列表跳转的详情页不同,携带面经文章id,只有一个参数,直接在地址栏携带动态传参比较方便),【详情页】渲染
    • 组件缓存,优化性能

在这里插入图片描述


二、素材

  1. 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')
  1. App.vue
<template>
  <div class="h5-wrapper">
      <!--路由出口-->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "h5-wrapper",
}
</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>
  1. router/index.js
import Vue from 'vue'
import VueRouter from "vue-router";
Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    
  ]
})

export default router
  1. views/
=====Article.vue=====

<template>
  <div class="article-page">
    <div
      class="article-item"
      >
      <div class="head">
        <img src="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="" />
        <div class="con">
          <p class="title">百度前端面经</p>
          <p class="other">青春, 那么骚 | 2022-01-20</p>
        </div>
      </div>
      <div class="body">
         虽然百度这几年发展势头落后于AT,甚至快被京东赶上了,毕竟瘦死的骆驼比马大,面试还是相当有难度和水准的。一面1.询问你的项目经验、学习经历、主修语言(照实答)2.解释ES6的暂时性死区( let 和 var 的区别)3.箭头函数、闭包、异步(老生常谈,参见上文)4.高阶函数(呃……我真不太清楚这是啥,听起来挺像闭包的)5.求N的阶乘末尾有多少个0,在线码代码或讲思路(求因数,统计2、5、10的个数
      </div>
      <div class="foot">点赞 44 | 浏览 315</div>
    </div>
  </div>
</template>

<script>
// 请求地址: https://mock.boxuegu.com/mock/3083/articles
// 请求方式: get
export default {
  name: 'ArticlePage',
  data () {
    return {

    }
  }
}
</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>
=====ArticleDetail.vue=====

<template>
  <div class="article-detail-page">
    <nav class="nav"><span class="back">&lt;</span> 面经详情</nav>
    <header class="header">
      <h1>百度前端面经</h1>
      <p>2022-01-20 | 315 浏览量 | 44 点赞数</p>
      <p>
        <img
          src="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",
  data() {
    return {
      
    }
  }
}
</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>
=====Layout.vue=====

<template>
  <div class="h5-wrapper">
    <div class="content">
      内容
    </div>
    <nav class="tabbar">
      <a href="#/article">面经</a>
      <a href="#/collect">收藏</a>
      <a href="#/like">喜欢</a>
      <a href="#/user">我的</a>
    </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>
=====Collect.vue=====

<template>
  <div>Collect</div>
</template>

<script>
export default {
  name: 'CollectPage'
}
</script>
=====Like.vue=====

<template>
  <div>Like</div>
</template>

<script>
export default {
  name: 'LikePage'
}
</script>
=====User.vue=====

<template>
  <div>User</div>
</template>

<script>
export default {
  name: 'UserPage'
}
</script>


三、路由配置

聚焦于:一级路由对应内容&子路由页面

在这里插入图片描述

①. 一级路由配置

代码实现

router/index.js文件中进行

…… ……
//导入一级路由
import Layout from '@/views/Layout.vue' 
import ArticleDetail from '@/views/ArticleDetail.vue'
…… ……
//
const router = new VueRouter({
  routes: [
    {
      path: '/',		//访问主页
      component: Layout		//渲染组件
    },
    {
      path: '/ArticleDetail',	//访问详情页
      component: ArticleDetail
    }
  ]
})

②. 二级路由配置

二级路由也叫嵌套路由,还可以嵌套三级、四级…

  1. 使用场景

    当在页面中点击链接跳转,只是部分内容切换时

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  2. 语法

    • 在一级路由下,配置==children属性==即可
    • 配置二级路由的出口
const router = new VueRouter({
  routes: [
    {
      path: '/',
      component: Layout,
      children:[
        //children中的配置项 跟一级路由中的配置项一模一样 
        {path:'xxxx',component:xxxx.vue},
        {path:'xxxx',component:xxxx.vue},
      ]
    }
  ]
})

注意

  • 一级的路由path 需要加 /; 二级路由的path可加可不加 /
  • 二级路由对应的组件渲染到哪个一级路由下,children就配置到哪个路由下边
代码实现-二级路由

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,
      children:[
        {
          path:'/Article',
          component:Article
        },
        {
          path:'/Collect',
          component:Collect
        },
        {
          path:'/Like',
          component:Like
        },
        {
          path:'/User',
          component:User
        }
      ]
    },
    {
      path:'/ArticleDetail',
      component:ArticleDetail
    }
  ]
})

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标签**<a></a>替换成<router-link></router-link>组件,配置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>

五、首页请求渲染

首页–>嵌套二级路由 面经–>文章列表–> Article.vue

核心步骤

1. 安装 axios

npm install axios或者yarn add axios

2. 看接口文档,确认请求方式,请求地址,请求参数
请求地址: https://mock.boxuegu.com/mock/3083/articles
请求方式: get
3. created中发请求,获取数据,存起来
async created(){
    const res=await axios.get('https://mock.boxuegu.com/mock/3083/articles')
    console.log(res);
  }

获取数据展示:

在这里插入图片描述
在这里插入图片描述

代码实现:
<script>
// 请求地址: https://mock.boxuegu.com/mock/3083/articles
// 请求方式: get
import axios from 'axios'
export default {
  name: 'ArticlePage',
  data () {
    return {
      articelList: []
    }
  },
  async created(){
    const res=await axios.get('https://mock.boxuegu.com/mock/3083/articles')
    // console.log(res);
    this.articles=res.data.result.rows
    console.log(this.articles);
  }
}
</script>

或者 进行解构

 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>

六、跳转传参

  • 查询参数传参
    • ?参数名=参数值
    • => this.$route.query.参数名
查询参数传参-代码实现:

Article.vue文件中进行

@click="$router.push(`/ArticleDetail?id=${item.id}`)"

ArticleDetail.vue文件中进行

created(){
	console.log(this.$route.query.id);
}
  • 动态路由传参(需要改造路由)
    • /路径/参数

    • this.$route.params.参教名

动态路由传参-代码实现:
  1. 改路由 加上/:id

router/index.js文件中进行

{
    path:'/ArticleDetail/:id',
    component:ArticleDetail
}
  1. Article.vue文件中进行
@click="$router.push(`/ArticleDetail/${item.id}`)"
  1. ArticleDetail.vue文件中进行
created(){
	console.log(this.$route.params.id);
}

七、修复

  1. 访问(/)首页 http://localhost:8080/#/页面出现大片空白

    原因:没有配置/所对应的规则,只对应Layout的架子,没有匹配任何二级子路由

    要求:一进页面看到【面经】

    解决:重定向

访问首页-代码实现:

router/index.js文件中进行

path:'/',
component: Layout,
//增加重定向
redirect:'/Article',
  1. 面经详情页返回按钮

ArticleDetail.vue文件中进行

以下两种都可以:

返回按钮-代码实现:
@click="$router.back()"//返回上一页
@click="$router.push('/article')"//跳转到文章列表

八、详情页渲染

 请求地址: https://mock.boxuegu.com/mock/3083/articles/:id
 请求方式: get
代码实现:

ArticleDetail.vue文件中进行

  1. 发送请求
<script>
import axios from 'axios'
// 请求地址: https://mock.boxuegu.com/mock/3083/articles/:id
// 请求方式: get
export default {
  name: "ArticleDetailPage",
  data() {
    return {
      articleDetail:{}
    }
  },
  async created() {
    const id = this.$route.params.id
    const {data:{result}} = await axios.get(
      `https://mock.boxuegu.com/mock/3083/articles/${id}`
    )
    this.articleDetail = result
  }
}
</script>
  1. 页面动态渲染
<template>
  <div class="article-detail-page">
    <nav class="nav">
      <span class="back" @click="$router.back()">&lt;</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>

九、组件缓存

  • 问题:从【面经】点到【详情页】,又点返回,数据重新加载了→ 希望回到原来的位置

  • 原因:路由跳转后,组件被销毁了,返回回来组件又被重建了,所以数据新被加

  • 解决:利用 keep-alive 将组件缓存下来

在这里插入图片描述

1.keep-alive是什么

keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。(作为容器)

2.keep-alive的优点

在组件切换过程中 把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验

<template>
  <div class="h5-wrapper">
    <keep-alive>
      <router-view></router-view>
    </keep-alive>
  </div>
</template>
演示:
<template>
  <div class="h5-wrapper">
    <!-- 包裹了keep-alive的两个一级路由组件都会被缓存 -->
    <!-- Layout和Article -->
    <keep-alive>
      <router-view></router-view>
    </keep-alive>
  </div>
</template>

问题:

点击详情页出去后滑动位置被缓存,但是重新点击另一个详情页,会显示上一个点击的详情页;

缓存了所有被切换的组件

3.keep-alive的三个属性

① include : 组件名数组,只有匹配的组件会被缓存

② exclude : 组件名数组,任何匹配的组件都不会被缓存

③ max : 最多可以缓存多少组件实例

语法:include / exclude 前不能忘记加上:

:include="['组件name属性']
//eg.     :include="['LayoutPage']

4.新增生命周期钩子(了解)

keep-alive的使用会触发两个生命周期函数

  • activated 当组件 被激活(使用) 的时候触发 -> 进入这个页面的时候触发

  • deactivated 当组件 不被使用 的时候触发 -> 离开这个页面的时候触发

  • 组件缓存后就不会执行组件的created,mounted,destroyed等钩子了,所以其提供了activeddeactived 钩子,帮我们实现业务需求

原-演示:

Layout.vue文件中进行

<script>
export default {
  name: "LayoutPage",
  created(){
    console.log('created 组件被加载了');
  },
  mounted(){
    console.log('mounted dom 渲染完了');
  },
  destroyed(){
    console.log('destroyed 组件被加载了');
  }
}
</script>

在这里插入图片描述

可以看到组件LayoutPage缓存了,没有执行其create,mounted,

注:create只在页面第一次加载时执行了,后来再返回首页的时候就没有执行了

新-演示:

在这里插入图片描述
在这里插入图片描述


十、修复

发现漏了一个小点,访问首页时,默认选择展示面经文章列表,但导航栏没有默认高亮

解决:【两种】

这是第一种:
  • 我使用了 Vue 的绑定语法 :class 来动态地添加 active 类到当前选中的导航链接上;
  • isPathActive 方法用于检查当前路由路径是否以给定的路径开头。如果匹配,则返回 true,并添加 active 类。
代码实现

Layout.vue文件中进行

<template>
  <div class="h5-wrapper">
    <div class="content">
      <!-- 内容 -->
      <router-view></router-view>
    </div>
    <nav class="tabbar">
      <router-link to="/article"  :class="{ active: isPathActive('/Article') }">面经</router-link>
      …… ……
    </nav>
  </div>
</template>

<script>
export default {
  name: "LayoutPage",
  methods: {  
    isPathActive(path) {  
      return this.$route.path.startsWith(path);  
    }  
  }  
}
</script>

<style>
    a.active {
      color: orange;
    }
</style>
这是第二种:

使用 router-linkrouter-link-active 属性来实现导航栏的高亮显示,而无需编写额外的 isPathActive 方法

router-link-active 属性会自动应用到当前路由激活(即当前被访问的)的 router-link

代码实现

Layout.vue文件中进行

  • 20
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值