Vue工程化-面经项目开发流程

项目目标

完成页面跳转,分清楚一级路由和二级路由的配置。

项目需求

在首页一栏,完成页面跳转,获取异步数据信息导入完成网页信息的浏览体验。

本项目只完成面经详情内容浏览。

项目组成

       一级路由

  1. 导航栏组件Layout.vue,导航内容包括:面经(预览),收藏,喜欢,我的。
  2. 网页首页显示栏即面经文章页面的预览。

        二级路由

     面经文章详情内容(ArticleDetail.vue),收藏一栏内容(Collect.vue),喜欢一栏内容(Like.vue),我的一栏内容(User.vue)

项目准备

       创建项目:vue create (项目名,选择vue2关键字项目)

       启动项目:导入vscode,安装依赖npm install ,运行项目npm run serve,初步运行

                            需要有插件VueRouter

      所涉及vue操作: 路由配置,axios异步操作数据。

代码操作

       配置组件:

      

1.组件代码逻辑:

导航栏Layout.vue
<template>
  <!-- 一级路由配置 -->
  <div class="h5-wrapper">
    <div class="content">
      <!-- 二级路由出口,匹配到的二级路由组件就会展示 -->
      <router-view></router-view> 
    </div>
    <nav class="tabbar">
      <!-- 底部导航栏 -->
      <!-- r<outer-link to="路由"></outer-link> -->
      <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;
    }
    a.active{
      color: orange;
    }
  }
}
</style>
面经预览一栏Article.vue
<template>
  <!-- 一级路由首页,面经页面一栏 -->
    <div class="article-page">
      <div class="article-item" v-for="(item) in articles" :key="item.id" 
          @click="$router.push(`/detail/${item.id}`)">
          <!-- @click="$router.push(`/detail/${item.id}`)" 
            跳转传参:唯一标识id响应数据内容  -->
        <div class="head">
          <img :src="item.creatorAvatar" alt="">
          <div class="con">
            <p class="title">{{item.stem}}</p>
            <p class="other">{{creatorName}} | {{creatorAt}}</p>
          </div>
        </div>
        <div class="body">
          {{item.content}}
        </div>
        <div class="foot">点赞 {{item.likeCount}} | 浏览 {{item.views}}</div>
      </div>
  </div>
</template>

<script>
//1,传输数据axios
import axios from 'axios'
export default {
  name: 'ArticlePage',
  data(){
    return{
      // 定义一个数组变量,用于接收异步数据
      articles:[]
    }
  },
  async created(){
    // 2,created中发送请求,获取异步数据,get 网址
    const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles');
    // 查看所获取数据信息,代码习惯
    // console.log(res);
    // 3,异步数据赋值操作,获取相关的数据,页面动态渲染
    this.articles = res.data.result.rows;
    // console.log(this.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>
收藏一栏Collect.vue
<template>
  <div>二级路由:“收藏”一栏</div>
</template>

<script>
export default {
  name: 'CollectPage'
}
</script>
喜欢一栏Like.vue
<template>
  <div>二级路由:“喜欢”一栏</div>
</template>

<script>
export default {
  name: 'LikePage'
}
</script>
我的一栏User.vue
<template>
  <div>二级路由:“我的”一栏</div>
</template>

<script>
export default {
  name: 'UserPage'
}
</script>
面经详情一栏ArticleDetail.vue
<template>
  <!-- 二级路由 “面经详情”一栏 -->
  <div class="article-detail-page" v-if="article.id">
    <!-- 返回上一页 @click="$router.back()" -->
    <nav class="nav"> <span @click="$router.back()" class="back">&lt;</span> 面经详情</nav>
    <header class="header">
      <h1>{{article.stem}}</h1>
      <p>{{article.creatAdt}} | {{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'
export default {
  name: 'ArticleDetailPage',
  data(){
    return{
      article:{}
    }
  },
  async created(){
    // created中发送请求,async获取异步数据,get 网址
    const id = this.$route.params.id;// 定义获取唯一标识id
    const {data} = await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${id}`)//根据唯一标识id获取对应的数据内容,{data}对象解构写法,直接获取到data数据内容
    this.article= data.result//动态渲染详情页内容
    // console.log(this.article);
  }
};
</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>

2.路由配置:

配置路径与组件的关系

./router/index.js

import Vue from 'vue'
import VueRouter from "vue-router"
import Layout from '@/views/Layout.vue'
import ArticleDetail from '@/views/ArticleDetail.vue'
import Article from '@/views/Article.vue'
import Collect from '@/views/Collect.vue'
import Like from '@/views/Like.vue'
import User from '@/views/User.vue'
Vue.use(VueRouter)

const router = new VueRouter({
    routes: [{
            path: '/',
            component: Layout,
            //重定向redirect,默认网页首页
            redirect: '/article',
            children: [
                { path: '/article', component: Article },
                { path: '/collect', component: Collect },
                { path: '/like', component: Like },
                { path: '/user', component: User },
            ]

        },
        // :id 根据唯一标识id获取对应的数据内容
        { path: '/detail/:id', component: ArticleDetail },

    ],
    linkActiveClass: 'active',
    linkExactActiveClass: 'exact-active'
})

export default 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')
Layout导航组件配置路由出口

根组件App.vue导入渲染:
<template>
  <div class="h5-wrapper">
    <!-- Layout组件中一有配置name属性,即LayoutPage,配置了name属性优先级于组件文件名称 -->
    <keep-alive :include="keepArr">
      <router-view></router-view>
    </keep-alive>
     <!-- keep-alive 当前缓存了一级路由组件,还包括Layout,ArticleDetail组件;
      缓存需要的组件使用include属性,只缓存需要缓存的组件,
      keep-alive缓存包含 :include="需要缓存的(组件名)或(name属性)或(缓存组件名的数组)"
      理解作用,就是返回该页面的时候,页面显示还是上一次浏览的位置,而不是重新回到页面加载 -->
  </div>
</template>

<script>
export default {
  name: 'h5-wrapper',
  data(){
    return {
      // 缓存组件名的数组
      keepArr:['LayoutPage']
    }
  }
}
</script>

<style>
body{
  margin: 0;
  padding: 0;
}
</style>

技术总结:

路由配置:

一级路由和二级路由的配置router

const router = new VueRouter({
    routes: [{
            path: '/',
            component: Layout,
            //重定向redirect,默认网页首页
            redirect: '/article',
            children: [
                { path: '/article', component: Article },
                { path: '/collect', component: Collect },
                { path: '/like', component: Like },
                { path: '/user', component: User },
            ]

        },
        // :id 根据唯一标识id获取对应的数据内容
        { path: '/detail/:id', component: ArticleDetail },

    ],
    //自定义设置高亮类名
    linkActiveClass: 'active',
    linkExactActiveClass: 'exact-active'
})
异步获取数据axios:
1.Article组件下获取数据:
<script>
//1,传输数据axios
import axios from 'axios'
export default {
  name: 'ArticlePage',
  data(){
    return{
     // 定义一个数组变量,用于接收异步数据
     articles:[]
    }
  },
  async created(){
    // 2,created中发送请求,获取异步数据,get 网址
    const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles');
    // 查看所获取数据信息,代码习惯
    // console.log(res);
    // 3,异步数据赋值操作,获取相关的数据,页面动态渲染
    this.articles = res.data.result.rows;
    // console.log(this.articles);查看所获取数据信息,代码习惯
  }
};

2.动态传参:

       在Article页面下点击文章详情,跳转ArticleDetail页面的操作:

<!-- @click="$router.push(`/detail/${item.id}`)" 跳转传参:唯一标识id响应数据内容  -->

        在ArticleDetail组件中,内容的展示获取,通过唯一标识id获取数据内容。

<script>
import axios from 'axios'
export default {
  name: 'ArticleDetailPage',
  data(){
    return{
      article:{}
    }
  },
  async created(){
    // created中发送请求,async获取异步数据,get 网址
    const id = this.$route.params.id;// 定义获取唯一标识id
    const {data} = await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${id}`)//根据唯一标识id获取对应的数据内容,{data}对象解构写法,直接获取到data数据内容
    this.article= data.result//动态渲染详情页内容
    // console.log(this.article);
  }
};
</script>
3.组件缓存:

       在根组件App.vue中配置

 keep-alive 当前缓存了一级路由组件,还包括Layout,ArticleDetail组件;

      缓存需要的组件使用include属性,只缓存需要缓存的组件,

      keep-alive缓存包含 :include="需要缓存的(组件名)或(name属性)或(缓存组件名的数组)"

      理解作用,就是返回该页面的时候,页面显示还是上一次浏览的位置,而不是重新回到页面加载

4.返回上一页:
<!-- 返回上一页 @click="$router.back()" -->

页面效果图

该项目参考为黑马练习项目,本人自学分享,有问题希望能够得到指正,欢迎讨论,共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值