關(guān)于VueRouter導(dǎo)入的全過程
router
nanoid的使用
? --生成隨機id
引入
yarn add nanoid
使用
import {nanoid} from 'nanoid' var id = nanoid()
路由
1-1 安裝依賴
yarn add vue-router
1-2 引入
router/index.js
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) import Movie from '../pages/Movie/index.vue' import Music from '../pages/Music/index.vue' const routes = [ { path:"/music", component:Music }, { path:"/movie", component:Movie } ] const router = new VueRouter({ routes, mode:"history" }) export default router;
1-3 在main.js中使用
import Vue from 'vue' import App from './App.vue' import router from './router' Vue.config.productionTip = false new Vue({ ? router, ? render: h => h(App), }).$mount('#app')
1-4 App.vue
<template> ? <div> ? ? <router-view></router-view> ? </div> </template>
全局過濾器
在main.js中掛載在Vue原型上
Vue.filter("handleStr",function(val){ ? if(val.length > 3){ ? ? val = val.slice(0,3) + '...' ? } ? return val })
element-ui
安裝依賴
yarn add element-ui
main.js
.... import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI); ...
全局組件
import Loading from '../components/Loading.vue' Vue.component("Loading",Loading)
Vuc-cli中的視配
只在手機端
lib-flexible 阿里
1-1 安裝依賴
yarn add lib-flexible postcss-pxtorem@5.1.1
1-2 配置文件
新建postcss.config.js
module.exports = { ? plugins: { ? ? 'postcss-pxtorem': { ? ? ? rootValue: 75, ? ? ? propList: ['*'], ? ? }, ? }, };
1-3 main.js
導(dǎo)入lib-flexible
import 'lib-flexible/flexible.js'
1-4 public/index.html
將此行注釋,關(guān)閉視口
<meta name="viewport" content="width=device-width,initial-scale=1.0">
1-5 在pc端視配
<template> ? <div id="app"> ? ? ... ? </div> </template>
<script> ?? ?... </script>
<style> *{ ? margin: 0; ? padding: 0; } #app{ ? width: 10rem; ? margin: 0 auto; ? background-color: red; } </style>
slot封裝動畫
// #1 定義一個組件 <template> ? <transition> ? ? <slot name="fade"></slot> ? </transition> </template>
<script> export default { } </script>
<style> .v-enter,.v-leave-to{ ? opacity: 0; } .v-enter-active,.v-leave-active{ ? transition: opacity 4s; } </style>
// #2 使用 <template> ? <div class="about"> ? ? <Fade> ? ? ? <h1 slot="fade" v-show="isShow">This is an about page</h1> ? ? </Fade> ? </div> </template>
<script> import Fade from '../components/Fade.vue' export default { ? data() { ? ? return { ? ? ? isShow:true ? ? } ? }, ? components:{ ? ? Fade ? } } </script>
項目初始化
1、rem 2、asssreset.css
1-1 .router-link-active
被選中的路由樣式
.router-link-active{ ? ? color: #ff2d51; ? }
1-2 動態(tài)顯示tabbar
? – 在路由配置中增加一條meta屬性
const routes = [ ? { ? ? path: '/films', ? ? name: 'Films', ? ? component:Films, ? ? meta:{ ? ? ? isNav:true ? ? } ? }, ? { ? ? path: '/article', ? ? name: 'Article', ? ? component:Article, ? ? meta:{ ? ? ? isNav:true ? ? } ? }, ? { ? ? path: '/center', ? ? name: 'Center', ? ? component:Center, ? ? meta:{ ? ? ? isNav:true ? ? } ? }, ? { ? ? path:"/movie/:id", ? ? name:'MovieDetail', ? ? component:MovieDetail ? } ]
通過v-if動態(tài)顯示
<tab-bar v-if="this.$route.meta.isNav"></tab-bar>
1-3 跳轉(zhuǎn)回前一個頁面
this.$router.back()
1-4輪播
yarn add vue-preview
import VuePreview from 'vue-preview' Vue.use(VuePreview)
vant ui的按需導(dǎo)入
1-1 安裝依賴
yarn add vant babel-plugin-import
1-2 配置babel.config.js
module.exports = { ? presets: [ ? ? '@vue/cli-plugin-babel/preset' ? ], ? plugins: [ ? ? ["import", { ? ? ? "libraryName": "vant", ? ? ? "libraryDirectory": "es", ? ? ? "style": true ? ? }] ? ] }
1-3 配置main.js
import {Button} from 'vant' Vue.use(Button)
router-view實現(xiàn)動畫
<template> ? <div> ? ? <div class="cover" v-if="isShow"></div> ? ? <transition? ? ? ? @before-enter="handleBeforeEnter" ? ? ? @enter="handleEnter" ? ? > ? ? ? <slot></slot> ? ? </transition> ? </div> </template>
<script> /*? .v-enter ? ? ? ? ? ? ?@before-enter .v-ernter-active ? ? ?@enter .v-enter-to ? ? ? ? ? @after-enter */ ? export default { ? ? data() { ? ? ? return { ? ? ? ? isShow:false ? ? ? } ? ? }, ? ? methods:{ ? ? ? handleBeforeEnter(){ ? ? ? ? this.isShow = true ? ? ? }, ? ? ? handleEnter(){ ? ? ? ? setTimeout(() => { ? ? ? ? ? this.isShow = false ? ? ? ? }, 200); ? ? ? } ? ? } ? } </script>
<style> ? .v-enter-active{ ? ? animation: animate 2s linear; ? } ? @keyframes animate { ? ? 0%{ ? ? ? opacity: 0; ? ? ? transform: translateY(0px); ? ? } ? ? 50%{ ? ? ? opacity: .5; ? ? ? transform: translateY(20px); ? ? } ? ? 100%{ ? ? ? opacity: 1; ? ? ? transform: translateY(0px); ? ? } ? } ? .cover{ ? ? width: 100%; ? ? height: 100%; ? ? background-color: #fff; ? ? position: fixed; ? ? z-index: 10; ? } </style>
嵌套路由
1-1 router.js
?{ ? ? path: '/films', ? ? name: 'Films', ? ? component:Films, ? ? meta:{ ? ? ? isNav:true ? ? }, ? ? children:[ ? ? ? { ? ? ? ? path:"nowPlaying", ? ? ? ? component:NowPlaying ? ? ? } ? ? ] ? },
1-2 index.vue
需要加入router-view
<template> ?? ?... ? ? <div class="container"> ? ? ? ? <!-- 裝載父路由下的子路由的對應(yīng) --> ? ? ? ? <router-view></router-view> ? ? </div> </template>
異步路由?
--又稱路由懶加載
{ ? ? path: '/about', ? ? name: 'About', ? ? // 異步路由 ? ? component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') },
怎么減少首屏渲染時間
1、使用異步路由
頁面跳轉(zhuǎn)和生命周期
? --面試???/p>
頁面跳轉(zhuǎn)
1-1 A頁面初次加載
beforeCreate(){ ?? ?console.log('beforeCreate'); }, created(){ ?? ?console.log('created'); }, beforeMount(){ ?? ?console.log('beforeMount'); }, mounted(){ ?? ?console.log('mounted'); },
1-2 A->B
從A頁面跳轉(zhuǎn)到B頁面
A頁面觸發(fā)以下生命周期
beforeDestroy(){ ?? ?console.log('beforeDestroy'); }, destroyed(){ ?? ?console.log('destroyed'); }
1-3 B–>A
從B頁面回到A頁面
A頁面觸發(fā)以下生命周期
beforeCreate(){ ?? ?console.log('beforeCreate'); }, created(){ ?? ?console.log('created'); }, beforeMount(){ ?? ?console.log('beforeMount'); }, mounted(){ ?? ?console.log('mounted'); },
upDate
beforeUpdate , beforeUpdate執(zhí)行需要滿足以下兩個條件
1、data中的數(shù)據(jù)更新的時候
2、模板中要使用data中的數(shù)據(jù)
destroyed
# A頁面 --> b頁面
b頁面執(zhí)行以下生命周期:
- 1.beforeCreate B
- 2.created B
- 3.beforeMount B
- 4.beforeDestroy A
- 5.destroyed A
- 6.mounted B
DOM和生命周期
只能在mounted生命周期中獲取DOM
緩存的進一步封裝
localStorage.setItem() 函數(shù)會將對象或者數(shù)組全部轉(zhuǎn)換成字符串的形式
所以可以對緩存進行判斷,使用 JSON.stringify 和 JSON.parse 分別處理數(shù)據(jù)
const setLocalStorage = (key , value) => { ? if(value instanceof Array || value instanceof Object){ ? ? value = JSON.stringify(value) ? } ? localStorage.setItem(key , value) } const getLocalStorage = (key) =>{ ? var val = localStorage.getItem(key) ? var reg = /^[[{].*[\]}]/ ? if(reg.test(val)){ ? ? val = JSON.parse(val) ? } ? return val }
axios
跨域
安裝依賴
yarn add axios-jsonp
axios格式
import axios from 'axios' import jsonpAdapter from 'axios-jsonp' axios({ ? ? url:"", ? ? adapter: jsonpAdapter, }).then( ?? ?res => console.log(res) )
騰訊地圖api需要在最后加上 &output=jsonp
https://apis.map.qq.com/ws/location/v1/ip?key=L6UBZ-JSLCU-FRAVA-4DBQG-V5WC5-2RBJ4&output=jsonp
地址值的放置
http://47.108.197.28:3000/top/playlist?limit=1&offset=1
在小程序中
wx.request({ })
axios中
import axios from 'axios' axios({ ?? ?url:"http://47.108.197.28:3000/top/playlist", ?? ?method:"get", ?? ?params:{ ?? ?limit:1 ?? ?} }).then(res=>{ ?? ?console.log(res) })
Vuex
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ ? state: { ? }, ? mutations: { ? }, ? actions: { ? }, ? modules: { ? } })
1、state
? --state中存放的是數(shù)據(jù)
state: { ? ? num:10 }
this.$store.state
2、mutation
? --mutation中的函數(shù)第一個默認參數(shù)是state
? --連接方式 commit
mutations: { ? ? add(state){ ? ? ? ? console.log(state); ? ? ? ? state.num++; ? ? } },
this.$store.commit('add')
3、actions
? --actions中的函數(shù)第一個默認值是上下文
? --連接方式 dispatch
actions: { ? ? addNum(ctx){ ? ? ? ? console.log(ctx); ? ? ? ? ctx.commit("add") ? ? } },
this.$store.dispatch('a')
keep-alive
- 使用keep-alive之后,路由切換的時候,生命周期函數(shù)不會重復(fù)的觸發(fā)
- 組件不會被銷毀,而是被緩存起來。當(dāng)加載到對應(yīng)的路由頁面,緩存的組件會被加載
路由組件的兩個生命周期函數(shù)
/* 路由組件被激活時觸發(fā)。 */ activated(){ ?? ?console.log('activated') } /* 路由組件失活時觸發(fā)。 */ deactivated(){ ?? ?console.log('deactivated') }
路由守衛(wèi)
全局路由守衛(wèi)
router.beforeEach((to , from ,next)=>{ ? console.log(to); ? ?// 要跳轉(zhuǎn)的路由 ? console.log(from); ?// 起點路由 ? next(); })
Login_guard(Vue&koa)
一、登錄頁面
<template> ? <div> ? ? <el-form ? ? ? :model="ruleForm" ? ? ? status-icon ? ? ? :rules="rules" ? ? ? ref="ruleForm" ? ? ? label-width="100px" ? ? ? class="demo-ruleForm" ? ? > ? ? <!-- props為了規(guī)則校驗 rules --> ? ? <el-form-item label="用戶名" prop="username"> ? ? ? ? <el-input ?type="text" v-model.number="ruleForm.username"></el-input> ? ? ? </el-form-item> ? ? ? <el-form-item label="密碼" prop="pass"> ? ? ? ? <el-input ? ? ? ? ? type="password" ? ? ? ? ? v-model="ruleForm.pass" ? ? ? ? ? autocomplete="off" ? ? ? ? ></el-input> ? ? ? </el-form-item> ? ? ? <el-form-item label="確認密碼" prop="checkPass"> ? ? ? ? <el-input ? ? ? ? ? type="password" ? ? ? ? ? v-model="ruleForm.checkPass" ? ? ? ? ? autocomplete="off" ? ? ? ? ></el-input> ? ? ? </el-form-item> ? ? ? <el-form-item> ? ? ? ? <el-button type="primary" @click="submitForm('ruleForm')" ? ? ? ? ? >提交</el-button ? ? ? ? > ? ? ? ? <el-button @click="resetForm('ruleForm')">重置</el-button> ? ? ? </el-form-item> ? ? </el-form> ? </div> </template> <script> export default { ? // beforeRouteEnter () { ? // ? /* 在局部守衛(wèi)中獲取不到this */ ? // ? console.log(1); ? // }, ? data() { ? ? var checkUsername = (rule, value, callback) => { ? ? ? if (!value) { ? ? ? ? return callback(new Error("用戶名不能為空")); ? ? ? }else{ ? ? ? ? callback(); ? ? ? } ? ? }; ? ? var validatePass = (rule, value, callback) => { ? ? ? if (value === "") { ? ? ? ? callback(new Error("請輸入密碼")); ? ? ? } else { ? ? ? ? if (this.ruleForm.checkPass !== "") { ? ? ? ? ? this.$refs.ruleForm.validateField("checkPass"); ? ? ? ? } ? ? ? ? callback(); ? ? ? } ? ? }; ? ? var validatePass2 = (rule, value, callback) => { ? ? ? if (value === "") { ? ? ? ? callback(new Error("請再次輸入密碼")); ? ? ? } else if (value !== this.ruleForm.pass) { ? ? ? ? callback(new Error("兩次輸入密碼不一致!")); ? ? ? } else { ? ? ? ? callback(); ? ? ? } ? ? }; ? ? return { ? ? ? ruleForm: { ? ? ? ? pass: "", ? ? ? ? checkPass: "", ? ? ? ? username: "", ? ? ? }, ? ? ? rules: { ? ? ? ? pass: [{ validator: validatePass, trigger: "blur" }], ? ? ? ? checkPass: [{ validator: validatePass2, trigger: "blur" }], ? ? ? ? username: [{ validator: checkUsername, trigger: "blur" }], ? ? ? }, ? ? }; ? }, ? methods: { ? ? submitForm(formName) { ? ? ? this.$refs[formName].validate((valid) => { ? ? ? ? if (valid) { ? ? ? ? ? // alert("submit!"); ? ? ? ? ? // console.log(this.ruleForm); ? ? ? ? ? // console.log(username,pass); ? ? ? ? ? /* 發(fā)送http請求 */ ? ? ? ? ? this.loginHttp() ? ? ? ? } else { ? ? ? ? ? console.log("error submit!!"); ? ? ? ? ? return false; ? ? ? ? } ? ? ? }); ? ? }, ? ? resetForm(formName) { ? ? ? this.$refs[formName].resetFields(); ? ? }, ? ? loginHttp(){ ? ? ? var {username , pass} = this.ruleForm ? ? ? this.$http({ ? ? ? ? method: 'post', ? ? ? ? url:'http://localhost:8000/login', ? ? ? ? data:{ ? ? ? ? ? username, ? ? ? ? ? pass ? ? ? ? } ? ? ? }).then(res=>{ ? ? ? ? console.log(res.data); ? ? ? ? if(res.data.code == 200){ ? ? ? ? ? this.$message({ ? ? ? ? ? ? message:res.data.msg, ? ? ? ? ? ? type:"success", ? ? ? ? ? ? duration:1000 ? ? ? ? ? }) ? ? ? ? ? this.$router.push('/home') ? ? ? ? }else{ ? ? ? ? ? this.$message({ ? ? ? ? ? ? message:res.data.msg, ? ? ? ? ? ? type:"warning", ? ? ? ? ? ? duration:1000 ? ? ? ? ? }) ? ? ? ? } ? ? ? }) ? ? } ? } ? }; </script>
二、后臺代碼
const koa = require("koa"); const app = ?new koa(); const koaBody = require("koa-body"); const router = require("koa-router")(); const cors = require("koa2-cors"); ? ? ? /* username=cheng ?pass=123456 */ ? ? console.log(ctx.request.body); ? ? var {username , pass } = ctx.request.body ? ? if(username == "cheng" && pass == "123456"){ ? ? ? ctx.cookies.set("loginAuth",true,{ ? ? ? ? /* httpOnly:false ? 設(shè)置前端可讀 */ ? ? ? ? httpOnly:false ? ? ? }) ? ? ? ctx.body = { ? ? ? ? code:200, ? ? ? ? msg:"登錄成功" ? ? ? } ? ? }else{ ? ? ? ctx.body = { ? ? ? ? code:400, ? ? ? ? msg:"登錄失敗,用戶名或密碼錯誤" ? ? ? } ? ? } }) /* 后端配置cookie可以實現(xiàn)跨域訪問 */ app.use(cors({ ? origin:ctx =>{ ? ? return ctx.headers.origin ? }, ? credentials:true })); app.use(koaBody()); app.use(router.routes()); app.listen(8000);
三、配置cookie跨域訪問
3-1 配置后端cookie可以訪問
/* 后端配置cookie可以實現(xiàn)跨域訪問 */ app.use(cors({ ? origin:ctx =>{ ? ? return ctx.headers.origin ? }, ? credentials:true }));
3-2 配置前端跨域訪問cookie
import axios from 'axios' /* 設(shè)置前端跨域訪問cookie */ axios.defaults.withCredentials = true axios.defaults.crossDomain = true
3-3 vue上獲取cookie
安裝依賴
yarn add vue-cookie
配置main.js
import VueCookie from 'vue-cookie' Vue.use(VueCookie)
在頁面中獲取cookie
mounted() { ? ? console.log(this.$cookie.get('loginAuth')); }
3-4 路由守衛(wèi)
? --沒有登錄的情況下,不能進入其它頁面
? --已經(jīng)登錄的情況下,直接進入首頁
var vm = new Vue(); router.beforeEach((to,from,next)=>{ ? console.log(vm.$cookie.get('loginAuth')); ? var isLogin = vm.$cookie.get('loginAuth') ? if(to.path == "/login"){ ? ? /* 1、登錄頁面,如果cookie顯示登錄了直接進入home頁面,如果沒有登錄,正產(chǎn)執(zhí)行l(wèi)ogin頁的邏輯 */ ? ? if(isLogin){ ? ? ? router.push('/home') ? ? }else{ ? ? ? next() ? ? } ? }else{ ? ? /* 2、在其他頁面,如果登錄正常顯示,沒有登錄則停留在login頁面 */ ? ? if(isLogin){ ? ? ? next() ? ? }else{ ? ? ? router.push('/login') ? ? } ? } })
懶加載
1、圖片懶加載
安裝依賴
yarn add vue-lazyload
在main.js中進行配置
import VueLazyLoad from 'vue-lazyload' Vue.use(VueLazyLoad,{ ? preLoad:1.3, ? loading:require('@/assets/loading.gif') })
使用(將:src替換成v-lazy)
<template> ? <div class="home"> ? ? <div ?v-for="item of playlists" :key="item.id"> ? ? ? <img ?class="item" v-lazy="item.coverImgUrl" alt=""> ? ? ? <p>{{item.name}}</p> ? ? </div> ? </div> </template>
2、axios攔截器
? --實現(xiàn)loading的加載效果
在vuex中定義一條isShowLoading --> 設(shè)置加載條是否顯示
export default new Vuex.Store({ ? state: { ? ? isSowLoading:true ? }, })
main.js
// 配置 請求攔截 和 響應(yīng)攔截 // 添加請求攔截器 axios.interceptors.request.use(function (config) { ? // 在發(fā)送請求之前做些什么 ? store.state.isSowLoading = true ? return config; }); // 添加響應(yīng)攔截器 axios.interceptors.response.use(function (response) { ? // 2xx 范圍內(nèi)的狀態(tài)碼都會觸發(fā)該函數(shù)。 ? // 對響應(yīng)數(shù)據(jù)做點什么 ? store.state.isSowLoading = false ? return response; });
App.vue設(shè)置loading
<template> ? <div id="app"> ? ? <Loading v-if="this.$store.state.isShowLoading"/> ? ? <router-view/> ? </div> </template>
3、上拉刷新
vant-ui 中整合了小程序中的 onBottom 和 onLoad
<template> ? <div class="home"> ? ? <van-list ? ? ? class="home" ? ? ? v-model="loading" ? ? ? :finished="finished" ? ? ? finished-text="沒有更多了" ? ? ? @load="onLoad" ? ? > ? ? ? <van-cell @click="handleClick(item.id)" v-for="item of playlists" :key="item.id"> ? ? ? ? <img class="item" v-lazy="item.coverImgUrl" alt=""> ? ? ? ? <p>{{item.name}}</p> ? ? ? </van-cell> ? ? </van-list> ? </div> </template>
<script> export default { ? name: 'Home', ? data() { ? ? return { ? ? ? playlists:[], ? ? ? loading:false, ? ? ? finished:false ? ? } ? }, ? mounted() { ? ?? ? }, ? methods: { ? ? onLoad(){ ? ? ? setTimeout(()=>{ ? ? ? ? var offset = this.playlists.length ? ? ? ? console.log(1); ? ? ? ? this.axios.get(`http://47.108.197.28:3000/top/playlist?offset=${offset}&limit=20`).then(res =>{ ? ? ? ? ? var playlists = this.playlists.concat(res.data.playlists) ? ? ? ? ? this.playlists = playlists ? ? ? ? ? this.loading = false ? ? ? ? }) ? ? ? },500) ? ? }, ? ? handleClick(id){ ? ? ? this.$router.push(`detail?id=${id}`) ? ? } ? }, } </script>
<style scoped> ? .item{ ? ? width: 150px; ? ? height: 150px; ? } ? .home{ ? ? display: flex; ? ? justify-content: space-between; ? ? flex-wrap: wrap; ? } ? .van-cell{ ? ? width: 150px; ? } ? .home >>> .van-list__loading{ ? ? position: fixed; ? ? bottom: 0; ? ? left: 50%; ? ? transform:translateX(-50%); ? } </style>
4、路由滾動記錄當(dāng)前滾動條位置問題?
在路由設(shè)置中,重置滾動條的x,y
const router = new VueRouter({ ? ... ? scrollBehavior (to , from , savedPosition) { ? ? if( to.path == "/detail"){ ? ? ? return {x:0,y:0}?? ?// 讓頁面出于頂部 ? ? }else{ ? ? ? return savedPosition?? ?// 讓頁面出于記錄點 ? ? } ? } })
Vue路由跳轉(zhuǎn)的bug
項目中遇到如下報錯內(nèi)容:
Uncaught (in promise) Error: Redirected when going from “/XXX” to “/XXX” via a navigation guard.
原因:vue-路由版本更新產(chǎn)生的問題,導(dǎo)致路由跳轉(zhuǎn)失敗拋出該錯誤,但并不影響程序功能
在main.js中改變push原型
import Router from 'vue-router' const originalPush = Router.prototype.push Router.prototype.push = function push(location, onResolve, onReject) { ? if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject) ? return originalPush.call(this, location).catch(err => err) }
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue使用el-table 添加行手動填寫數(shù)據(jù)和刪除行及提交保存功能
遇到這樣的需求點擊新增按鈕實現(xiàn)下列彈窗的效果,點擊添加行新增一行,點擊刪除進行刪除行,點擊提交將數(shù)據(jù)傳遞到后端進行保存,怎么實現(xiàn)的呢,下面通過實例代碼給大家詳細講解,感興趣的朋友一起看看吧2023-12-12el-tree使用獲取當(dāng)前選中節(jié)點的父節(jié)點數(shù)據(jù)
本文主要介紹了el-tree使用獲取當(dāng)前選中節(jié)點的父節(jié)點數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-10-10vue安裝node-sass和sass-loader報錯問題的解決辦法
這篇文章主要給大家介紹了關(guān)于vue安裝node-sass和sass-loader報錯問題的解決辦法,文中通過圖文以及示例代碼將解決的方法介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2023-01-01淺談VUE單頁應(yīng)用首屏加載速度優(yōu)化方案
這篇文章主要介紹了淺談VUE單頁應(yīng)用首屏加載速度優(yōu)化方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08