1. vue-cli 構(gòu)建項(xiàng)目
- 命令行
# 全局安裝 vue-cli
$ npm install --global vue-clif
# 創(chuàng)建一個(gè)基于 webpack 模板的新項(xiàng)目
$ vue init webpack your-project-name
# 安裝依賴,走你
$ npm install
# 進(jìn)入項(xiàng)目
$ cd your-project-name
# 開發(fā)版本打包并運(yùn)行
$ npm run dev
# 線上環(huán)境整個(gè)項(xiàng)目打包 生成 dist 可以直接部署到服務(wù)器上的文件夾
npm run build
2. 項(xiàng)目模板中使用 less 方法
原文地址
vue-cli 構(gòu)建的項(xiàng)目默認(rèn)是不支持 less 的,需要自己添加。
- 首先安裝 less 和 less-loader ,在項(xiàng)目目錄下運(yùn)行如下命令
# npm安裝
$ npm install less less-loader --save-dev
# 或者使用 yarn
$ yarn add less less-loader --dev
- 安裝成功后审磁,打開
build/webpack.base.conf.js
,在 module.exports = 的對象的 module.rules 后面添加一段:
module.exports = {
// 此處省略無數(shù)行,已有的的其他的內(nèi)容
module: {
rules: [
// 此處省略無數(shù)行烦绳,已有的的其他的規(guī)則
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader",
}
]
}
}
- 最后在代碼中的 style 標(biāo)簽中 加上 lang="less" 屬性即可
<style scoped lang="less">
</style>
- 之后在項(xiàng)目中測試是否成功
npm install less less-loader --save-dev
npm run dev
- 在瀏覽其中打開相應(yīng)頁面,這個(gè)頁面是
/
根頁面點(diǎn)擊跳轉(zhuǎn)過來的子路由
可以看到樣式編譯成功了 哦耶~
3. 在 router 下的路由文件里設(shè)置格式配紫,將頁面上路由中默認(rèn)顯示的 #/
給去掉
// 去掉路由中自帶的 #/ 這種東西
mode: 'history',
- 需要注意的是使用了
history
之后需要在服務(wù)器部署時(shí)增加一些配置径密,具體方法插件下面官方寫的配置方法
4. 引入 jquery
- 安裝
npm install jquery --save
- 配置
// 先在頂部引入 webpack
const webpack = require('webpack')
// plugins 中添加
new webpack.ProvidePlugin({
'window.jQuery': 'jquery', // 為了兼容其他的插件
jQuery: 'jquery',
$: 'jquery'
})
- 使用
5. :class 使用表達(dá)式
:class="{'想要改變的類名': 判斷條件}
- 示例圖片
6. DOM 事件修飾符
<!-- 阻止單擊事件繼續(xù)傳播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修飾符可以串聯(lián) -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件監(jiān)聽器時(shí)使用事件捕獲模式 -->
<!-- 即元素自身觸發(fā)的事件先在此處處理,然后才交由內(nèi)部元素進(jìn)行處理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只當(dāng)在 event.target 是當(dāng)前元素自身時(shí)觸發(fā)處理函數(shù) -->
<!-- 即事件不是從內(nèi)部元素觸發(fā)的 -->
<div v-on:click.self="doThat">...</div>
- 示例躺孝,如下圖所示享扔,這樣寫的話點(diǎn)擊了 li 內(nèi)部的元素的話不會(huì)影響 li 的 click 的點(diǎn)擊事件
7. vue 使用 clipboard 實(shí)現(xiàn)復(fù)制功能
- 安裝依賴 clipboard.js
npm install clipboard --save
- 在需要使用的地方 require 引用
var clipboard = require('clipboard');
- 在頁面加載后調(diào)用該方法即可
8. 解決 vue-resource 的跨越問題
我這里是 vue-cli 基于 webpack 的項(xiàng)目(注意:在修改了 proxyTable 之后需要在命令行中
npm run dev
重新運(yùn)行下項(xiàng)目底桂,否則是不會(huì)有效果的呀~)
- 錯(cuò)誤信息
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
- 解決方法:
先找到對應(yīng)的配置 js 文件中的 proxyTable
修改相應(yīng)的配置
再在 main.js 中配置 vue-resource 的格式,不配置的話是無法向后臺(tái)傳遞參數(shù)的
在 vue 文件中的使用
data 中綁定相應(yīng)的靜態(tài)配置
methods 增加相應(yīng)的方法
mouted 在 data 數(shù)據(jù)掛載到實(shí)例對象的時(shí)候 惧眠,請求頁面數(shù)據(jù)籽懦,實(shí)現(xiàn)頁面的正常顯示
9. vue-router 單頁之間如何在 js 中跳轉(zhuǎn)
- 三種寫法
// 字符串
this.$router.push('/home/first')
// 對象
this.$router.push({ path: '/home/first' })
// 命名的路由
this.$router.push({ name: 'home', params: { userId: wise }})
10. vuex 實(shí)現(xiàn)組件之間數(shù)據(jù)的傳遞
根據(jù) state 可以實(shí)時(shí)的獲取到數(shù)據(jù)
原文地址
- 安裝
npm install vuex --save
- 在 src 文件夾中新建一個(gè) stroe 文件夾,并在目錄下新建一個(gè) index.js 文件(已有的話請忽略)氛魁,index.js 文件編輯如下
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
let store = new Vuex.Store({
state: {
formData: {} // 企業(yè)提交數(shù)據(jù)表單對象
}
});
export default store;
- 在 src 目錄下的 main.js 文件中引入 vuex 文件暮顺,并在實(shí)例化時(shí)添加配置
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store'; // 引入 vuex
Vue.config.productionTip = false;
Vue.http.options.emulateJSON = true;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store, // 需要在添加
components: { App },
template: '<App/>'
});
- 之后就可以直接在需要的組件中直接引用,引用具體示例如下
控制臺(tái)成功輸出
11. .eslintrc.js 文件 rules 增加設(shè)置
12. vue 表單操作
13. 解決使用 vux 組件庫時(shí) 與 rem 設(shè)置沖突帶來的問題
- 思路
將之前 rem 計(jì)算的數(shù)值
html font-size: "100px"
秀存,改到12px
捶码,之后連鎖的將 less 中計(jì)算和引用的的值也改下,之后就可以了或链,盡量做到少量的修改即可
- 將之前的 js 計(jì)算 rem 數(shù)值腳本修改相應(yīng)的數(shù)值
改過之后的
- 修改 less
改過之后的
- 之后就可以是 rem 和 vux 基本正常了
14. 通過 watch 動(dòng)態(tài)的監(jiān)測路由跳轉(zhuǎn)(跳轉(zhuǎn)時(shí))和 APP.vue 中設(shè)置 created 方法實(shí)時(shí)監(jiān)測 path (刷新時(shí))惫恼,來實(shí)現(xiàn) header 文字的改變
- header.vue
watch: {
'$route' (to, from) {
// 檢測路由改變 header 內(nèi)容
if (to.name === 'Index') {
this.$store.state.PageTitle = '預(yù)約領(lǐng)號(hào)';
this.$store.state.isShowBack = false;
} else if (to.name === 'PreferentialDescription') {
this.$store.state.PageTitle = '優(yōu)惠說明';
this.$store.state.isShowBack = true;
} else if (to.name === 'RuleIntroduction') {
this.$store.state.PageTitle = '規(guī)則簡介';
this.$store.state.isShowBack = true;
} else if (to.name === 'ReservationSuccess') {
this.$store.state.PageTitle = '預(yù)約排號(hào)';
this.$store.state.isShowBack = true;
}
}
}
15. vue-router spa (單頁)需要的 nginx 配置,防止出現(xiàn) 404 的情況
照著上方的圖將代碼復(fù)制至服務(wù)器的 nginx.config 配置文件即可
- ssh 遠(yuǎn)程登錄服務(wù)器
ssh username@ipaddress
enter your password
- 查找服務(wù)器中的 nginx 相關(guān)目錄澳盐,我這邊是 nginx 服務(wù)器
whereis nginx
-
/etc/nginx
這個(gè)是 nginx 相關(guān)配置的目錄 -
/usr/share/nginx
是靜態(tài)文件的目錄 - 進(jìn)入 html 目錄祈纯,這個(gè)就是默認(rèn)的存放項(xiàng)目文件的目錄
- 修改 nginx 默認(rèn)的配置文件
# 首先進(jìn)入配置文件目錄
cd /etc/nginx
ls
# 查看配置文件
cat nginx.config
# 復(fù)制一份原始的配置文件
cp nginx.config nginx.config.back
# 按照上面 vue-router 的需求修改配置文件
vi nginx.config
# 進(jìn)入編輯狀態(tài)
I
# 修改文件
location / {
try_files $uri $uri/ /index.html;
}
# 之后保存并退出
esc
:
wq
# 再次查看是否已修改成功
cat nginx.config
# 重載 nginx 配置文件(必須重載,不然修改的是不會(huì)生效的叼耙!)
nginx -s reload
- 上面的步驟操作完成之后便解決了 vue-router spa 帶來的刷新頁面 404 的問題了盆繁,哦耶~
16. 與后臺(tái) API 進(jìn)行通信時(shí),Content-Type
請求文本格式未統(tǒng)一帶來的問題
- 問題截圖
后臺(tái)返回 415 Unsupported Media Type
對于當(dāng)前請求的方法和所請求的資源旬蟋,請求中提交的實(shí)體并不是服務(wù)器中所支持的格式油昂,因此請求被拒絕。
- 產(chǎn)生錯(cuò)誤的原因:
這里使用的是
post
請求倾贰,后臺(tái)的請求文本格式為Content-Type:application/json;charset=UTF-8
但是這里使用的是默認(rèn)的Content-Type:application/x-www-form-urlencoded
所以造成的此次錯(cuò)誤
- 解決方法
在提交數(shù)據(jù)之前使用
JSON
的stringify
方法將數(shù)據(jù)轉(zhuǎn)換為 json 格式的文本即可冕碟,如下圖所示
JSON.stringiy()
JSON.stringify() 方法是將一個(gè)JavaScript值(對象或者數(shù)組)轉(zhuǎn)換為一個(gè) JSON字符串,如果指定了replacer是一個(gè)函數(shù)匆浙,則可以替換值安寺,或者如果指定了replacer是一個(gè)數(shù)組,可選的僅包括指定的屬性首尼。
17. 清除 .vue
文件在 vscode 編輯器中格式化時(shí)默認(rèn)添加的分號(hào)和雙引號(hào)的規(guī)則
- 問題
因?yàn)?
vue-cli
項(xiàng)目創(chuàng)建后會(huì)默認(rèn)的增加.eslintrc.js
eslint 規(guī)則文件來幫助我們更好的統(tǒng)一代碼的規(guī)范性挑庶,但是現(xiàn)在的趨勢是省略javascript
代碼書寫時(shí)在末尾添加的分號(hào),但是 vscode 編輯器因?yàn)檠b了vetur
這個(gè)插件软能,所以還是會(huì)像之前的那樣默認(rèn)追加迎捺,使得項(xiàng)目報(bào) eslint 語法的錯(cuò)誤,單雙引號(hào)也是相同的問題
- 解決方法
先安裝擴(kuò)展插件
Prettier - Code formatter
之后在頂部菜單欄依次操作:【文件】->【首選項(xiàng)】->【設(shè)置】->【用戶設(shè)置】
最后增加下面的規(guī)則代碼片段
"prettier.singleQuote": true,
"prettier.semi": false
18. 之前的刪掉了查排,等待更新中......
19. 給 vue
掛載全局方法
- 找到
main.js
文件進(jìn)行編輯凳枝,這里以axios
為例演示
import Vue from 'vue'
import axios from 'axios'
Vue.prototype.axios = axios
- 使用方法 某個(gè)
.vue
文件的sccript
中如下編輯
Vue.axios.post('url', { name: '' })
.then(response => {
console.log(response)
})
.catch(response => {
console.log(response)
})
.finally(() => (me.loading= false));
20. axios
不兼容 ie 的問題解決
- 問題描述
在 IE 瀏覽器下會(huì)報(bào) “Promise”未定義" 的錯(cuò)誤
- 資料
問題解決參考地址
- 解決方法
使用 babel-polyfill 這個(gè)包
- 裝包
yarn add babel-polyfill --dev
- 之后在
main.js
文件中引入包即可
import 'babel-polyfill'
- 測試可兼容至 IE8+
- 更新 優(yōu)化進(jìn)階 已經(jīng)過測試
參考文章里面有詳細(xì)的解釋:babel-polyfill使用與性能優(yōu)化
目的是為了打包出更小的體積,下圖是使用新方法打包出的體積跋核,用上面的方法打包出來是2.64MB
- 解決方法 將之前引入的
babel-polyfill
換成core-js/es6/promise
這個(gè)是vue-cli
腳手架就有的包無需再裝了
import 'core-js/es6/promise' // 解決 axios 兼容 IE 問題
21. 組件封裝岖瑰,這里以 bootstrap 的 modal 模塊為例
- 先寫組件叛买,在
src -> components
目錄下新建一個(gè)文件夾msgmodal -> index.vue
,編輯如下
<template>
<!-- 彈窗 -->
<div class="modal fade" tabindex="-1" role="dialog" id="myModal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<!-- <h5 class="modal-title"></h5> -->
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>{{ modalMsg }}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">確定</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">關(guān)閉</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'MsgModal', // 定義的組件名稱 使用時(shí)寫法:msg-modal
props: ['modalMsg'] // 定義的與父級(jí)通信的屬性值 使用時(shí)寫法:modal-msg
}
</script>
<style scoped>
</style>
- 在具體的
.vue
文件使用組件蹋订,方法如下率挣,這里是用的動(dòng)態(tài)綁定的方法傳遞屬性的值
<!-- template -->
<!-- 彈窗 -->
<msg-modal :modal-msg="modalMsg"></msg-modal>
// script
import MsgModal from '@/components/msgmodal'
export default{
name:'App',
components: { MsgModal },
data () {
return {
// 彈窗信息 在執(zhí)行操作時(shí)使用
modalMsg: ''
}
}
}
- 測試,已實(shí)現(xiàn)可以實(shí)時(shí)更新內(nèi)容了
22. 在 router -> index.js
按需引入模塊露戒,優(yōu)化 SPA
頁面的性能
- 源碼
import Vue from 'vue'
import Router from 'vue-router'
import VueResource from 'vue-resource'
// import index from '@/index'
// import companyapply from '@/companyapply'
// import choosenumber from '@/choosenumber'
// import statelist from '@/statelist'
Vue.use(Router)
Vue.use(VueResource)
export default new Router({
// 去掉路由中自帶的 #/ 這種東西
mode: 'history',
routes: [
{
path: '/',
name: 'index',
component: () => import('@/index')
},
{
path: '/companyapply',
name: 'companyapply',
component: () => import('@/companyapply')
},
{
path: '/choosenumber',
name: 'choosenumber',
component: () => import('@/choosenumber')
},
{
path: '/statelist',
name: 'statelist',
component: () => import('@/statelist')
}
]
})
23. 在 Vue
上掛載 vux
庫中的 LoadingPlugin
組件
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import { LoadingPlugin } from 'vux' // 引入 looding 組件
import App from './App'
import store from './store' // 引入 vuex
import router from './router'
Vue.config.productionTip = false
Vue.http.options.emulateJSON = true
Vue.use(LoadingPlugin) // 掛載 loading 組件
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store, // 需要在添加
components: { App },
template: '<App/>'
})
-
.vue
文件中具體的使用示例:
// loading
this.$vux.loading.show({
text: '數(shù)據(jù)提交中
})
// 隱藏 loading
this.$vux.loading.hide()
24. 解決:使用 axios
默認(rèn)發(fā)送的是 application/json;charset=UTF-8
這種格式的數(shù)據(jù)后臺(tái)無法讀取的問題
后臺(tái)需要的是
application/x-www-form-urlencoded
這樣的數(shù)據(jù)格式
參考地址
- 問題截圖
- 需要的格式截圖
-
解決方法
- 使用
qs
模塊椒功,轉(zhuǎn)換數(shù)據(jù)格式
- 源碼
import qs from 'qs' // 解決 axios 數(shù)據(jù)提交格式與后臺(tái)不一致的問題 -> name=hehe&age=10 axios.post(postAPI,qs.stringify(postData)) .then(request => { console.log(request) }) .catch(error => { console.log(error) })
- 使用
25. 化繁為簡的Watchers
- 場景還原:
created(){
this.fetchPostList()
},
watch: {
searchInputValue(){
this.fetchPostList()
}
}
組件創(chuàng)建的時(shí)候我們獲取一次列表,同時(shí)監(jiān)聽input框玫锋,每當(dāng)發(fā)生變化的時(shí)候重新獲取一次篩選后的列表這個(gè)場景很常見蛾茉,有沒有辦法優(yōu)化一下呢讼呢?
- 招式解析:
首先撩鹿,在watchers中,可以直接使用函數(shù)的字面量名稱悦屏;其次节沦,聲明immediate:true表示創(chuàng)建組件時(shí)立馬執(zhí)行一次。
watch: {
searchInputValue:{
handler: 'fetchPostList',
immediate: true
}
}
26. 父子組件通信 -- 子組件可以調(diào)用父組件的方法
- 實(shí)現(xiàn)思路
使用
this.$emit()
以下示例為分頁組件础爬,下面只是將主要的部分代碼貼出
- 父組件
<template>
<!-- 分頁 -->
<pagination @updatePageData="loadPageData"></pagination>
</template>
<script>
export default{
methods:{
loadPageData:function(){
// do something
}
}
}
<script>
- 上面代碼的說明
@updatePageData="loadPageData"
:傳遞方法時(shí)前面使用@
甫贯;updatePageData
是給子組件使用的 父組件loadPageData
方法的別名
- 子組件
export default{
methods:{
pageGo:function(){
const me = this
// 調(diào)用父組件方法
me.$emit('updatePageData')
}
}
}
27. 父子組件通信 -- 子組件可動(dòng)態(tài)獲取父組件的數(shù)據(jù)
- 問題描述
由于父組件的數(shù)據(jù)是動(dòng)態(tài)獲取的,而子組件初始化時(shí)如果獲取不到數(shù)據(jù)就
Game Over
- 實(shí)現(xiàn)思路
使用
props
傳數(shù)據(jù) 看蚜;watch
監(jiān)聽數(shù)據(jù)
以下示例為分頁組件叫搁,下面只是將主要的部分代碼貼出
- 父組件
<template>
<!-- 分頁 -->
<pagination :parentPageData="pageGetData"></pagination>
</template>
<script>
export default{
data(){
return{
pageGetData:[]
}
},
methods:{
getData:function(){
// ajax 請求之后改變 pageGetData 的數(shù)據(jù)
}
}
}
<script>
- 上面代碼的說明
:parentPageData="pageGetData"
傳遞方法前面使用:
;parentPageData
是給子組件使用的 父組件pageGetData
數(shù)據(jù)的別名
- 子組件
export default{
props:['parentPageData'], // 父組件數(shù)據(jù) 別名
watch:{
// 監(jiān)聽父組件數(shù)據(jù)變化實(shí)時(shí)更新數(shù)據(jù)
parentPageData:{
handler: 'loadPageList',
immediate: true
}
},
methods:{
// 加載頁面數(shù)據(jù)
loadPageList:function(){
// do something
}
}
}
28. vue 多頁面開發(fā)分頁組件 有搜索功能
29. Vue
在 .vue
文件的樣式 style
標(biāo)簽中使用 background:url()
引入圖片
參考資料 vue 背景圖引入
- 示例代碼片段
<style scoped>
.loading {
position: fixed;
left: 0;
top: 0;
background: url('~@/assets/img/loading-ball.svg') center center no-repeat #fff;
width: 100vw;
height: 100vh;
z-index: 1000;
}
</style>
30. 頁面加載數(shù)據(jù)之前增加 loading
動(dòng)畫
31. 封裝一個(gè) axios
的通用方法
- 思路
自定義一個(gè)函數(shù)供炎,將其掛載到
Vue
對象的prototype
上面渴逻,方便在頁面使用,因?yàn)?axios
一般得和qs
模塊配合使用
qs 使用參考地址
- 在
main.js
文件中掛載自定義方法
import Vue from 'vue'
import 'babel-polyfill' // 解決 axios 兼容 IE 問題
import qs from 'qs' // 解決 axios 數(shù)據(jù)提交格式與后臺(tái)不一致的問題 -> name=hehe&age=10
import axios from 'axios'
// import router from './router'
import '@/assets/css/common.css'
import App from './index.vue'
Vue.config.productionTip = false
/**
* 自定義一個(gè)方法封裝 axios 請求音诫,并將其掛載至 Vue 原型鏈
* @param {string} url axios 請求的地址
* @param {string} dataJson axios 向請求地址發(fā)送的 json 數(shù)據(jù)
* @param {function} sucessFn axios 成功回調(diào)函數(shù)
* @param {function} errorFn axios 失敗回調(diào)函數(shù)
*/
Vue.prototype.axiosFn = function(url, dataJson, sucessFn, errorFn) {
axios
.post(url, qs.stringify(dataJson))
.then(response => {
console.log(response)
sucessFn()
})
.catch(error => {
console.log(error)
errorFn()
})
}
/* eslint-disable no-new */
new Vue({
el: '#app',
// router,
components: { App },
template: '<App/>'
})
- 具體的使用就不寫了,只需要在調(diào)用方法
axiosFn
時(shí)給其傳相應(yīng)的參數(shù)即可
32. 滿足:點(diǎn)擊當(dāng)前元素時(shí),其子元素不會(huì)被點(diǎn)中滞欠,且還會(huì)執(zhí)行回調(diào)事件--修改當(dāng)前樣式
- 思路:
現(xiàn)在的需求是有一個(gè)列表燥滑,每個(gè)列表元素也是一個(gè)有子元素的嵌套元素,點(diǎn)擊列表的每個(gè)子元素時(shí)給當(dāng)前列表添加類名
正常使用官網(wǎng)提供的 事件處理 — Vue.js 文檔香罐,無法實(shí)現(xiàn)想要的效果卧波,因?yàn)辄c(diǎn)擊傳遞的$event
是當(dāng)前點(diǎn)擊的事件,target
無法只得到列表的每個(gè)元素庇茫,相對其子元素而言就是父級(jí)元素
以前解決該方法的時(shí)候使用的是較為笨的方法:判斷target
元素幽勒,將其強(qiáng)行指向列表元素這樣子
- 新方法
給每個(gè)列表元素里面的子元素設(shè)置
css
屬性pointer-events: none;
,這樣的話也無需給@click
添加什么修飾符即可實(shí)現(xiàn)需求
33. 子頁面中在接口請求的時(shí)候港令,需要主頁面 App.vue
中請求到的接口的返回值啥容,特殊情況下會(huì)出現(xiàn) Bug
- 錯(cuò)誤重現(xiàn)
頂部是公用的導(dǎo)航組件锈颗,數(shù)據(jù)在App.vue
中請求,之后存進(jìn)store
中去咪惠,因?yàn)槭?keep-alive
击吱,所以正常情況下頂部的數(shù)據(jù)在第一個(gè)頁面載入時(shí)便會(huì)儲(chǔ)存到store
中,但是如果是第二個(gè)頁面(因?yàn)橹挥羞@個(gè)頁面會(huì)需要上面的聯(lián)系電話
的數(shù)據(jù))ctrl+f5
強(qiáng)制刷新后遥昧,store
中的數(shù)據(jù)會(huì)被清空覆醇,這樣如果在子頁面請求時(shí)沒有及時(shí)的將主頁面中請求到的數(shù)據(jù)聯(lián)系電話
存入store
中的話,便會(huì)出現(xiàn)子頁面請求時(shí)獲取聯(lián)系電話
字段為空的情況炭臭,主要就是因?yàn)檎埱笫峭桨l(fā)生的永脓,加載的延遲很低,應(yīng)該是主頁面請求完成之后子頁面再請求這樣子鞋仍。
- 解決
bug
后的源碼示例App.vue
文件
<template lang="pug">
#app
.header-box(v-loading="layoutHeaderLoading")
LayoutHeader
.nav-box
LayoutNav
keep-alive
.router-view(v-if="loadGuestRecord")
router-view
</template>
<script>
import LayoutNav from "@/components/LayoutNav";
import LayoutHeader from "@/components/LayoutHeader";
import { layoutHeader } from "@/api";
export default {
components: { LayoutNav, LayoutHeader },
data() {
return {
// 是否加載 loading
layoutHeaderLoading: false,
// 頂部 header 數(shù)據(jù)對象
headerInformation: {},
// 解決 “聯(lián)系電話”未儲(chǔ)存到 store 中常摧,所產(chǎn)生的 bug
loadGuestRecord: true
};
},
created() {
const me = this;
me.getPageData();
},
watch: {
$route(to, from) {
const me = this;
// 對路由變化作出響應(yīng)...
to.path === "/guestRecord" &&
!me.$store.getters.getMobile &&
(me.loadGuestRecord = false);
}
},
methods: {
/**
* 獲取頂部 header 數(shù)據(jù)
*/
getPageData() {
const me = this;
me.layoutHeaderLoading = true;
layoutHeader
.getCusUserInfo()
.then(resolve => {
console.log(resolve);
resolve.data.code === 200 &&
(me.headerInformation = resolve.data.data);
me.$store.commit("updateMobile", me.headerInformation.mobile);
})
.catch(error => {
console.log(error);
})
.finally(() => {
me.layoutHeaderLoading = false;
!me.loadGuestRecord && (me.loadGuestRecord = true);
});
}
}
};
</script>
- 解決思路,解釋上面的代碼
主要是
頂部的全局請求.then( 單頁請求 )這個(gè)樣子的
威创,下面是具體的實(shí)施方案:
在主頁面 data 中增加一個(gè)布爾變量落午,默認(rèn)為true,用它來指令是否 v-if 加載子頁面 router-view 肚豺,watch.$route 中判斷路由以及其他條件溃斋,為否 布爾變量 = false,再在主頁面的請求中 .finally( 布爾變量 = true )
34. router-link
導(dǎo)航接收并傳遞全部的 url
參數(shù)
- 先說思路:
在主頁面
App.vue
文件中吸申,接收所有的參數(shù)并將其傳遞給nav
導(dǎo)航
- 源碼示例:
- 主文件
App.vue
<template lang="pug">
#app
.header-box(v-loading="layoutHeaderLoading")
LayoutHeader(:header-information="headerInformation")
.nav-box
LayoutNav(:url-query="urlQuery")
keep-alive
.router-view(v-if="loadGuestRecord")
router-view
</template>
<script>
import LayoutNav from "@/components/LayoutNav";
import LayoutHeader from "@/components/LayoutHeader";
import { layoutHeader } from "@/api";
export default {
components: { LayoutNav, LayoutHeader },
data() {
return {
// 是否加載 loading
layoutHeaderLoading: false,
// 頂部 header 數(shù)據(jù)對象
headerInformation: {},
// 接受頁面的所有參數(shù)梗劫,并將其賦值到 router-link 參數(shù)上面
urlQuery: {}
};
},
created() {
const me = this;
me.getPageData();
},
watch: {
$route(to, from) {
const me = this;
me.urlQuery = to.query;
}
}
};
</script>
- 組件
LayoutNav.vue
<template lang="pug">
nav.nav
ul.nav-list
li.nav-item(v-for="(item,index) in routers" :key="item.id")
router-link(:to="{ name: item.link, query: urlQuery }")
.nav-icon
i(:class="item.icon")
h3.nav-title {{ item.name }}
</template>
<script>
import { routers } from "./config.json";
export default {
name: "layoutNav",
props: {
urlQuery: Object
},
data() {
return {
routers: routers
};
}
};
</script>
35. 項(xiàng)目增加權(quán)限
- 思路:
- 首先做的項(xiàng)目是從別的項(xiàng)目中跳轉(zhuǎn)過來的,所以有
權(quán)限
的需求 - 判斷權(quán)限的主要步驟:
- 先增加一個(gè)
401
無權(quán)限頁面 - 注冊一個(gè)全局前置守衛(wèi)
- 在守衛(wèi)中判斷加密字符是否一致截碴,路由跳轉(zhuǎn)至相應(yīng)的頁面去
- 在
App.vue
文件中梳侨,使用全局的組件時(shí),增加一個(gè)布爾變量
控制是否展示組件隐岛,默認(rèn)為false
展示組件猫妙,true
是不展示組件,如果watch.$route.to.path === "/401"
聚凹,這個(gè)布爾變量
便為true
- 先增加一個(gè)
36. 使用 beforeRouteLeave
銷毀組件割坠,實(shí)現(xiàn)組件的實(shí)時(shí)化
- 代碼
// 導(dǎo)航離開該組件的對應(yīng)路由時(shí)調(diào)用 [可以訪問組件實(shí)例 `this`] https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E7%BB%84%E4%BB%B6%E5%86%85%E7%9A%84%E5%AE%88%E5%8D%AB
beforeRouteLeave(to, from, next) {
// 銷毀組件,避免通過 vue-router 再次進(jìn)入時(shí)妒牙,仍是上次的 history 緩存的狀態(tài)
this.$destroy(true);
next();
}
37. 使用官方提供的 component
彼哼,根據(jù)條件循環(huán)判斷使用不同的組件
- 代碼(其中
van
相關(guān)的組件使用方法請查看 vant 官網(wǎng))
<template lang="pug">
.integrated-query
van-tabs(v-model="tabActive" color="#39a0ff" line-width="40" sticky)
van-tab(v-for="item in tabTitleList" :key="item.value" :title="item.name" :name="item.value")
component(:is="item.value")
</template>
<script>
export default {
name: "integratedQuery",
components: {
Overview: () => import("./components/Overview"),
Product: () => import("./components/Product"),
Accounting: () => import("./components/Accounting"),
Order: () => import("./components/Order"),
Assets: () => import("./components/Assets"),
Discount: () => import("./components/Discount"),
Invoice: () => import("./components/Invoice"),
VirtualNetwork: () => import("./components/VirtualNetwork")
},
data() {
return {
tabTitleList: [
{
name: "總覽",
value: "overview"
},
{
name: "產(chǎn)品",
value: "product"
},
{
name: "賬務(wù)",
value: "accounting"
},
{
name: "訂單",
value: "order"
},
{
name: "資產(chǎn)",
value: "assets"
},
{
name: "優(yōu)惠",
value: "discount"
},
{
name: "發(fā)票",
value: "invoice"
},
{
name: "虛擬網(wǎng)",
value: "virtual-network"
}
],
tabActive: "overview"
};
},
}
</script>
38. 基于 vue-cli
腳手架 官方配置 在配置文件中 vue.config.js
引入樣式預(yù)處理器共享的全局變量。
- 配置方式
module.exports = {
/**
* css 相關(guān)配置
*/
css: {
loaderOptions: {
stylus: {
import: "~@/common/stylus/mixin.styl"
}
}
}
}
39. el-input
使用 @keyup.enter
無效
需要添加
.native
修飾符
- 代碼示例
el-input(placeholder="請輸入內(nèi)容" v-model="dataListQuery.queryKey" size="small" clearable @keyup.enter.native="getDataList(leftTreeSelect.id)")
40. el-table
使用 toggleAllSelection
方法無效
需要在函數(shù)中湘今,增加一個(gè)參數(shù)
true
- 代碼示例
this.$refs.dialogTable.toggleAllSelection(true)
41. el-select
選中之后敢朱,數(shù)據(jù)無法回顯
- 需求描述
目前是有一個(gè)彈窗,內(nèi)部有一個(gè)表格,表格內(nèi)部的每一條數(shù)據(jù)都是可以單獨(dú)編輯的拴签,有
input
也有select
- 問題描述
當(dāng)我選中維表或者賬期下拉選項(xiàng)之后孝常,相對
v-model
綁定的數(shù)據(jù)字段已經(jīng)成功更新了,但是在el-select
組件中顯示不出來字典相應(yīng)的文本
- 問題解決
經(jīng)過幾個(gè)小時(shí)的反復(fù)試驗(yàn)蚓哩,最終確定是由于我綁定的數(shù)據(jù)字段构灸,并不是在數(shù)據(jù)初始化時(shí)(接口獲取的時(shí)候)定義的,所導(dǎo)致的字段無法及時(shí)更新的問題岸梨。
- 下面簡單描述下我具體的錯(cuò)誤方式:
接口獲取完數(shù)據(jù)喜颁,我并沒有在這個(gè)時(shí)候增加一些需要初始化的字段,而是選擇在將接口數(shù)據(jù)賦值給彈窗子組件的
form
之后曹阔,再在彈窗子組件中進(jìn)行了字段的初始化半开,由于我每次賦值都是使用的ES6
對象解構(gòu)賦值的方式,所以最終導(dǎo)致解構(gòu)出的變量已經(jīng)不是最初始賦值時(shí)的對象赃份,也就無法同步更新form
表單中的數(shù)據(jù)寂拆。
所以最終的解決方法就是,在接口獲取完數(shù)據(jù)芥炭,當(dāng)時(shí)就增加一些初始化必要的字段漓库。
42. 父組件使用 v-model
傳值給子組件恃慧,實(shí)現(xiàn)子組件可以同步更新父組件的 v-model
綁定的值
- 參考資料
- 具體實(shí)現(xiàn)的主要代碼
- 父組件
<template lang="pug">
.content
child-el(v-model="data")
</template>
<script>
import "childEl" from "./components"
export default {
components: {
childEl
},
data() {
return {
data: ""
}
}
}
</script>
- 子組件
<template lang="pug">
.content
.text(@click="handleClick") {{ data }}
</template>
<script>
export default {
model: {
prop: "data",
event: 'change'
},
props: {
data: {
type: String,
default: ""
}
},
methods: {
handleClick() {
this.$emit("change", "測試文本")
}
}
}
</script>
43. 當(dāng)使用 v-for
循環(huán)生成 dom
時(shí)园蝠,當(dāng)需要再增加 ref
屬性時(shí),獲取組件時(shí)需要加一個(gè)下標(biāo) [0]
- 代碼
//- 組件容器
.tab-content(v-for='item in navListData', :key='item.value')
.tab-bar {{ item.name }}
component(:is='item.value', :ref='item.value')
const componentsList = ['Overview', 'Volume', 'Industry', 'Monographic']
componentsList.forEach((element) => {
const component = this.$refs[`${element}`]
console.log(component)
component && component.length && component[0].getPageData(this.pagePostData)
})
44. 偶發(fā)事件痢士,在 v-if
判斷較多彪薛,層級(jí)嵌套較深內(nèi)部也有 v-if
或者 v-show
時(shí),會(huì)出現(xiàn)祖先級(jí) dom
可以渲染怠蹂,但是內(nèi)部的所有子級(jí) dom
無法正常渲染的 bug
這里我暫時(shí)采用的解決方案是將祖先級(jí)元素的
v-if
修改為v-show
45. 使用 vuex
進(jìn)行數(shù)據(jù)更新的時(shí)候善延,如果 val
是沒有變化的 set
,那么是不會(huì)被 watch
捕獲到的
<template lang="pug">
//- 通用的 下載文件過大城侧,提示彈窗
.download-tip
//- 彈窗內(nèi)容
el-dialog(
title='下載提示',
width='450px',
:visible.sync='dialogVisible',
:append-to-body='true',
@close='SetDownloadTipVisible(false)'
)
.dialog-content
.dialog-details
.dialog-text 由于當(dāng)前數(shù)據(jù)下載量過大易遣,系統(tǒng)將采取異步下載方式,#[br] 請到 #[el-button.color-blue(type='text', @click='checkDownloadTask') 下載界面] 查看下載進(jìn)度嫌佑。
.dialog-button
el-button(
type='primary',
size='small',
@click='SetDownloadTipVisible(false)'
) 我知道了
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
export default {
name: 'DownloadTip',
data() {
return {
dialogVisible: false
}
},
computed: {
...mapGetters(['downloadTipVisible'])
},
watch: {
// 監(jiān)測 store 中的 downloadTipVisible豆茫,實(shí)時(shí) 顯示/關(guān)閉 彈窗
downloadTipVisible: {
handler(val) {
this.dialogVisible = val
}
}
},
methods: {
...mapActions(['SetDownloadTaskVisible', 'SetDownloadTipVisible']),
/**
* 查看 通用下載任務(wù)列表
*/
checkDownloadTask() {
this.SetDownloadTipVisible(false)
this.SetDownloadTaskVisible(true)
}
}
}
</script>
<style lang="stylus" scoped>
.el-dialog__wrapper
>>>
.el-dialog__body
padding 0
.el-dialog__header, .el-dialog__footer
display none
.dialog-content
padding 245px 40px 20px
background url('~@/assets/common/img-download.png') top center no-repeat
background-size 100% auto
text-align center
.dialog-details
color #999
line-height 22px
.el-button--text
padding 0
.dialog-button
padding 30px 0
</style>
以上述代碼為例:
downloadTipVisible
是store
中的變量,如果它的當(dāng)前的值是false
屋摇,那么SetDownloadTipVisible(false)
時(shí)揩魂,watch
中時(shí)無法捕獲并及時(shí)更新的,所以需要在store
初始化時(shí)炮温,將downloadTipVisible
設(shè)置為false
和dialogVisible
一致火脉,這樣它們才能實(shí)時(shí)同步。(2021.7.12 續(xù):但是這樣好像也沒必要多聲明一個(gè)dialogVisible
了 /汗)
45. 利用 .sync
修飾符,讓子組件更新父組件的值倦挂,常用于彈窗組件的顯示/隱藏
- 主要的源碼部分示例:
- 父組件
<template lang="pug">
.data-lifecycle-preparedness
.page-content(v-show='!performDetailsShow')
perform-details(
v-if='performDetailsShow',
v-model='detailsData',
:perform-details-show.sync='performDetailsShow'
)
</template>
<script>
export default {
name: 'dataLifecycleIndex',
data() {
return {
performDetailsShow: false,
detailsData: {
key: 'test'
}
}
}
</script>
- 子組件
<template lang="pug">
.perform-details
.page-content
el-button.is-active(
plain,
icon='el-icon-back',
size='small',
@click='backClickHandler'
) 返回
</template>
<script>
export default {
name: 'PerformDetails',
model: {
prop: 'detailsData',
event: 'change'
},
props: {
detailsData: {
type: Object,
default: () => {}
},
performDetailsShow: {
type: Boolean,
default: true
}
},
methods: {
/**
* 返回 按鈕 點(diǎn)擊回調(diào)
*/
backClickHandler() {
this.$emit('update:performDetailsShow', false)
this.$emit('change', {})
}
}
}
</script>
是的畸颅,示例中不止使用了
.sync
還有常用的v-model
46. 某些特定的時(shí)候,會(huì)有需要同時(shí) watch
兩個(gè)不同的屬性的需求方援,這時(shí)可以使用 computed
新增屬性來實(shí)現(xiàn)
- 具體實(shí)現(xiàn)的主要代碼實(shí)例
import { mapGetters, mapActions } from 'vuex'
import commonAPI from '@/api/common'
export default {
computed: {
...mapGetters(['sidebar', 'commonPageData', 'tabInfo', 'activeMenuId']),
// 雖然最終想要的結(jié)果是實(shí)現(xiàn)了重斑,但是 watch 時(shí)會(huì)執(zhí)行兩次,請求兩次接口肯骇,因?yàn)?isChangeReport 會(huì)改變兩次
isChangeReport() {
const { $route, activeMenuId } = this
return {
$route,
activeMenuId
}
}
},
watch: {
isChangeReport: {
handler(val) {
console.log(val)
const { $route, activeMenuId } = this
if (activeMenuId && !$route.path.includes('serviceAnalysisCommon')) {
commonAPI.getMenuDetailsData(activeMenuId).then((res) => {
const { description } = res
this.SetCommonPageData({
title: description ? '報(bào)表介紹' : '',
content: description || ''
})
})
} else {
this.SetCommonPageData({
title: '',
content: ''
})
}
},
immediate: true
}
},
methods: {
...mapActions(['SetCommonPageData'])
}
}