Vue从入门到实战Day06

一、路由进阶

1. 路由模块封装

路由的封装抽离

问题:所有的路由配置都堆在main.js中合适么?

目标:将路由模块抽离出来。

好处:拆分模块,利于维护

示例:

router/index.js

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 },
  ]
})

export default router

2. 声明式导航  - 导航链接

需求:实现导航高亮效果

vue-router提供了一个全局组件router-link(取代a标签)

能跳转,配置to属性指定路径(必须)。本质还是a标签,to无需 #

能高亮(自带激活时的类名),默认就会提供高亮类名,可用直接设置高亮样式

示例:

App.vue

<template>
  <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>
</template>

<script>
export default {};
</script>

<style>
body {
  margin: 0;
  padding: 0;
}
.footer_wrap {
  position: relative;
  left: 0;
  top: 0;
  display: flex;
  width: 100%;
  text-align: center;
  background-color: #333;
  color: #ccc;
}
.footer_wrap a {
  flex: 1;
  text-decoration: none;
  padding: 20px 0;
  line-height: 20px;
  background-color: #333;
  color: #ccc;
  border: 1px solid black;
}
/* 高亮 */
.footer_wrap a.router-link-active {
  background-color: purple;
}
.footer_wrap a:hover {
  background-color: #555;
}
</style>

效果:

3. 导航高亮 - 两个类名

说明:我们发现router-link自动给当前导航添加了两个高亮类名

①精确匹配 - router-link-exact-active

如,to="/my",仅可以匹配 /my

②模糊匹配 - router-link-active(用的多)

如,to="/my",可以匹配 /my、/my/a、/my/b ······

示例:

App.vue

<template>
  <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>
</template>

<script>
export default {};
</script>

<style>
body {
  margin: 0;
  padding: 0;
}
.footer_wrap {
  position: relative;
  left: 0;
  top: 0;
  display: flex;
  width: 100%;
  text-align: center;
  background-color: #333;
  color: #ccc;
}
.footer_wrap a {
  flex: 1;
  text-decoration: none;
  padding: 20px 0;
  line-height: 20px;
  background-color: #333;
  color: #ccc;
  border: 1px solid black;
}
/* 
  router-link-active 模糊匹配(更多)
  to="/find"  =>  地址栏 /find   /find/one   /find/two  ...

  router-link-exact-active 精确匹配
  to="/find"  =>  地址栏 /find  
*/

/* 模糊匹配 */
.footer_wrap a.router-link-active {
  background-color: purple;
}

/* 精确匹配 */
/* .footer_wrap a.router-link-exact-active {
  background-color: purple;
} */

.footer_wrap a:hover {
  background-color: #555;
}
</style>

效果:模糊匹配

4. 自定义高亮类名 

说明:router-link的两个高亮类名太长了,我们希望能定制怎么办?

const router = new VueRouter({
    routes: [···],
    linkActiveClass: "类名1",
    linkExactActiveClass: "类名2"
    // linkActiveClass: "active",
    // linkExactActiveClass: "exact-active"
})

7. 声明式导航 - 跳转传参(查询参数传参 & 动态路由传参)

目标:在跳转路由时,进行传值

1. 查询参数传参(比较适合传多个参数)

①语法格式如下

  • to="/path?参数名=值&参数名2=值"

②对应页面组件接收传递过来的值

  • $route.query.参数名

示例:

views/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?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>

views/Search.vue

<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>

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

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>

效果:

2. 动态路由传参(优雅简洁,传单个参数比较方便)

①配置动态路由

const router = new VueRouter({
    routes: [
        ···,
        {
            path: '/search/:words',
            component: Search
        }
    ]
})

②配置导航链接

to="/path/参数值"

③对应页面组件接收传递过来的值

$route.params.参数名

示例:

router/index.js

views/Home.vue

views/Search.vue

动态路由参数可选符

问题:配了路由path:"/search/:words",为什么按下面步骤操作,会未匹配到组件,显示空白?

原因:/search/:words表示,必须要传参数。如果不传参数,也希望匹配,可以加个可选符"?"

const router = new VueRouter({
  routes: [
    { path: '/', redirect: '/home' },
    { path: '/home', component: Home },
    { path: '/search/:words?', component: Search }
  ]
})

8. Vue路由 - 重定向 

问题:网页打开,url默认是 / 路径,未匹配到组件时,会出现空白

  说明:重定向 -> 匹配path后,强制跳转path路径

语法:{path: 匹配路径, redirect: 重定向到的路径}

const router = new VueRouter({
  routes: [
    { path: '/', redirect: '/home' },
    { path: '/home', component: Home },
    { path: '/search/:words?', component: Search }
  ]
})

9. 路由404 

作用:当路径找不到匹配时,给个提示页面

位置:配在路由最后

语法:path: "*"(任意路径) - 前面不匹配就命中最后这个

const router = new VueRouter({
  routes: [
    { path: '/', redirect: '/home' },
    { path: '/home', component: Home },
    { path: '/search/:words?', component: Search },
    { path: '*', component: NotFound }
  ]
})

效果:

10. Vue路由 - 模式设置

问题:路由的路径看起来不自然,有#,能否切成真正路径形式?

  • hash路由(默认),例如:http://localhost:8080/#/home
  • history路由(常用),例如:http://localhost:8080/home(以后上线需要服务器端支持)
const router = new VueRouter({
    routes,
    mode: "history"
})

效果:

11. 编程式导航 - 基本跳转

问题:点击按钮跳转如何实现?

编程式导航:用JS代码来进行跳转

两种语法:

①path路径跳转(简易方便)

this.$router.push('路由路径')

this.$router.push({
    path: '路由路径'
})

②name命名路由跳转(适合path路径长的场景)

this.$router.push({
    name: '路由名'
})
{ name: '路由名', path: '/path/xxx', component: XXX },

12. 编程式导航传参(查询参数传参 & 动态路由传参)

问题:点击搜索按钮,跳转需要传参如何实现?

两种传参方式:查询参数 + 动态路由传参

两种跳转方式,对于两种传参方式都支持:

①path路径跳转传参

  • 查询参数传参
this.$router.push('/路径?参数名1=参数值1&参数2=参数值2')
this.$router.push({
    path: '/路径',
    query: {
        参数名1: '参数值1',
        参数名2: '参数值2'
    }
})
  • 动态路由传参
this.$router.push('/路径/参数值')
this.$router.push({
    path: '/路径/参数值'
})

②name命名路由跳转传参

  • 查询参数传参
this.$router.push({
    name: '路由名',
    query: {
        参数名1: '参数值1',
        参数名2: '参数值2'
    }
}
  • 动态路由传参
this.$router.push({
    name: '路由名字',
    params: {
        参数名: '参数值',
    }
})

示例代码:

<template>
  <div class="home">
    <div class="logo-box"></div>
    <div class="search-box">
      <input v-model="inpValue" type="text">
      <button @click="goSearch">搜索一下</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',
  data() {
    return {
      inpValue: ''
    }
  },
  methods: {
    goSearch() {
      // (4)path路径跳转传参
        // this.$router.push(`/search?key=${this.inpValue}`)
        // this.$router.push({
        //   path: '/search',
        //   query: {
        //     key: this.inpValue,
        //   }
        // })

      // this.$router.push(`/search/${this.inpValue}`)
      // this.$router.push({
      //   path: `/search/${this.inpValue}`,
      // })

      // (5)通过命名路由的方式跳转(需要给路由起名字)适合长路由
      this.$router.push({
        name: 'search',
        // query: {
        //   key: this.inpValue
        // }
        params: {
          words: this.inpValue
        }
      })
    }
  }
}
</script>

小结:

1. 编程式导航,如何跳转传参?

(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: {
        参数名: '参数值',
    }
})

13. 组件缓存 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>

问题:缓存了所有被切换的组件

3. keep-alive的三个属性

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

②exclude:组件名数组,任何匹配的组件都不会被缓存(容易出现性能问题);

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

<template>
    <div class="h5-wrapper">
        <keep-alive :include="['LayoutPage']">
            <router-view></router-view>
        </keep-alive>
    </div>
</template>

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

①activated:组件激活时触发 -> 进入页面触发

②deactivated:组件失活时 -> 离开页面触发

二、综合案例:面经基础版

一级路由 二级路由 导航高亮 请求渲染 路由传参 缓存组件

分析:配路由 + 实现功能

1. 配路由

①首页 和 面经详情页,两个一级路由

②首页内嵌4个可切换页面(嵌套二级路由:children

src/router/index.js

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';
import Vue from 'vue'
import VueRouter from "vue-router";
Vue.use(VueRouter)

const router = new VueRouter({

  routes: [
    { 
      path: '/', 
      component:Layout,
      redirect: '/article',
      // 通过children配置项,可以配置嵌套子路由
      // 1. 在children配置项中,配规则
      // 2. 准备二级路由出口
      children: [
        {
          path: '/article', 
          component:Article
        },
        {
          path: '/collect',
          component: Collect
        },
        {
          path: '/like',
          component: Like
        },
        {
          path: '/user',
          component: User
        }
      ]
    },
    { 
      path: '/detail/:id', 
      component:ArticleDetail
    },
    
  ]
})

export default router

main.js

2. 实现功能

①首页请求渲染

跳转传参 到详情页,详情页渲染

组件缓存: keep-alive,优化性能

src/views/Home.vue

<template>
  <div class="home">
    <div class="logo-box"></div>
    <div class="search-box">
      <input v-model="inpValue" type="text">
      <button @click="goSearch">搜索一下</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',
  data() {
    return {
      inpValue: ''
    }
  },
  methods: {
    goSearch() {
      // 通过路径的方式跳转
      // (1)this.$router.push('路由路径') [简写]
      // this.$router.push('/search')

      // (2)this.$router.push({ [完整写法]
      //      path: '路由路径'
      // })
      // this.$router.push({
      //   path: '/search'
      // })

      // (3)name命名
      // this.$router.push({
      //   name: 'search'
      // })

      // (4)path路径跳转传参
        // this.$router.push(`/search?key=${this.inpValue}`)
        // this.$router.push({
        //   path: '/search',
        //   query: {
        //     key: this.inpValue,
        //   }
        // })

      // this.$router.push(`/search/${this.inpValue}`)
      // this.$router.push({
      //   path: `/search/${this.inpValue}`,
      // })

      // (5)通过命名路由的方式跳转(需要给路由起名字)适合长路由
      this.$router.push({
        name: 'search',
        // query: {
        //   key: this.inpValue
        // }
        params: {
          words: this.inpValue
        }
      })
    }
  }
}
</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>

src/views/Layout.vue

<template>
  <div class="h5-wrapper">
    <div class="content">
      <!-- 二级路由出口,匹配到的二级路由出口组件就会展示 -->
      <router-view></router-view>
    </div>
    <nav class="tabbar">
      <!-- 导航高亮
        1. 将a标签,替换成router-link(to)
        2. 结合高亮类名实现高亮效果(router-link-active模糊匹配)
      -->
      <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,才会找文件名作为组件名
  name: "LayoutPage",

  // 一旦组件被缓存了,就不会执行组件的created、mounted、destroyed等钩子
  // 所以提供了 activated 和 deactivated
  created() {
    console.log('created 组件被加载了')
  },
  mounted() {
    console.log('mounted dom渲染完了')
  },
  destroyed() {
    console.log('destroyed 组件被销毁了')
  },
  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;
    }
    a.router-link-active {
      color: orange;
    }
  }
}
</style>

src/views/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="" />
        <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>
// 请求地址: https://mock.boxuegu.com/mock/3083/articles
// 请求方式: get

// 首页请求渲染
// 1. 安装axios: npm install axios
// 2. 查看接口文档,确认请求方式,请求地址,请求参数
// 3. 在created中发请求,获取数据,存起来
// 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')
    // console.log(res)
    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>

src/views/ArticleDetail.vue

<template>
  <div class="article-detail-page" v-if="article.id">
    <nav class="nav"><span @click="$router.back()" class="back">&lt;</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",
  async created() {
    // console.log(this.$route.params.id)
    const id = this.$route.params.id
    const {data} = await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${id}`)
    // console.log(res)
    this.article = data.result
    // console.log(this.article)
  },
  data() {
    return {
      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>

src/views/Collect.vue

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

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

src/views/Like.vue

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

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

src/views/User.vue

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

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

App.vue

<template>
  <div class="h5-wrapper">
    <keep-alive :include="keepArr">
      <!-- 包裹了keep-alive 一级路由匹配的组件都会被缓存
        Layout组件 Detail组件,都会被缓存。多两个生命周期钩子
        - activated 激活时,组件被看到时触发
        - deactivated 失活时,离开页面组件看不见时触发

        需求:只希望缓存LayoutPage,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>

三、自定义创建项目

1. 基于VueCli自定义创建项目架子

项目创建步骤:

①打开cmd,输入vue ui,打开Vue项目管理器界面

②填写项目名称

③预设选择“手动”

④勾选Babel、Router、CSS、Linter四项

⑤配置如下,然后创建项目,不保存为预设

⑥创建完成

⑦启动项目

2. ESlint代码规范

目标:认识代码规范

代码规范:一套写代码的约定规则。

例如:“赋值符号的左右是否需要空格” “一句结束是否需要加;”······

JavaScript Standard Style规范说明:https://standardjs.com/rules-zhcn.html

目标:学会解决代码规范错误

如果你的代码不符合standard的要求,ESlint会跳出来刀子嘴,豆腐心地提示你。

比如:在main.js中随意做一些改动,添加一些分号,空行。

两种解决方案:

手动修正:根据错误提示一项一项手动修改纠正。如果不认识命令行中的语法报错是什么意思,根据错误去[ESLint规则表]中查找具体含义。

自动修正:基于vscode插件ESLint高亮错误,并通过配置自动帮助我们修复错误。

// 当保存的时候,eslint自动帮我们修复错误
"editor.codeActionsOnSave": {
    "source.fixAll": true
},
// 保存代码,不自动格式化
"editor.formatOnSave": false

配置小步骤:

(1)点击右下角的设置;

(2)点击右上角的“打开设置”图表;

(3)在打开的settings.json添加上面的配置代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值