最近在用vue2.0做微信公眾號相關的前端開發,經過這次開發實踐,現將項目中用到的相關比較實用的插件及遇到的相關問題進行整理,希望和大家共同交流......
- cssrem:一個CSS值轉REM的VSCode插件;
- lib-flexible:移動端彈性布局適配解決方案;
- vue-touch:移動端相關點擊,滑動,拖動,多點觸控等事件封裝;
- vee-validate:適用於vue項目中表單驗證插件;
- better-scroll :可能是目前最好用的移動端滾動插件;
- fastclick:解決移動端click 300ms延遲
- vConsole:手機前端開發調試利器
- webpack之proxyTable設置跨域
- vue組件之間通信(父向子通信,子向父通信,非父子通信)方法示例;
- ref特性的使用;
- vue中setTimeout,setInterval的使用;
- 監聽鼠標滾動事件,實現頭部懸浮效果(this.$nextTick);
- new FormData()上傳圖像;
- vue,@click="event()",添加()與不添加()的區別;
1、cssrem
介紹:
一個CSS值轉REM的VSCode插件。我們在做移動端開發時,為了網頁適配,一般會將像素單位px轉換為rem.在用vscode開發時,我們可以安裝cssrem這個插件。
插件效果如下:
默認配置:
“cssrem.rootFontSize”: root font-size (unit: px), 默認為: 16; “cssrem.fixedDigits”: px轉rem小數點最大長度,默認:6; “cssrem.autoRemovePrefixZero”:自動移除0開頭的前綴,默認:true; "css.remoteStyleSheets": []
項目中配置:
“cssrem.rootFontSize”:75, //px轉化為rem基准75px,由於我在項目中使用了淘寶彈性布局方案lib-flexible,UI同事是按照iphone6尺寸(750px)進行設計的。項目在iphone6屏幕時,root,html的font-size:75px;所以,項目中配置rem基准為75px;
"cssrem.fixedDigits:2", 即設置px轉rem最大小數點為2位數;
使用方法:
這里是vsCode的配置方法:
文件-->首選項--設置-->“搜索cssrem”,將自己的設置放入右邊覆蓋“默認設置”,重啟編輯器,即可,如圖:
2、lib-flexible
介紹:lib-flexible為移動端彈性布局適配解決方案。很多的大公司,如網易,淘寶等,都在用它作為移動端布局。
使用方法:
- 安裝lib-flexible:
npm install lib-flexible --save
- 引入lib-flexible,在項目入口文件main.js 中引入lib-flexible
import 'lib-flexible'
- 去掉目標文件的index.html頭里的meta標簽。
<meta name="viewport" content="width=device-width, initial-scale=1.0">
不要寫上邊這行meta,flexible會為根據屏幕自動給我加上,如果你自己加了, 那么flexible會根據你加的值來計算,也就會出現固定的值,安卓和蘋果都會一樣了。data-dpr有可能是固定的了
知識延伸:
px2rem-loader,在做像素單位適配的時,你也可以不用安裝cssrem,直接用px,我們可以通過安裝插件:px2rem-loader並進行相應的配置,通過編譯之后,自動將px轉換為rem;
使用方法,可參考官網;但是其有一定的局限性,即只能將.vue文件style標簽中的px轉成rem,對外部引入css,px2rem能不能轉換rem問題;
對於引入了第三方框架,他們的樣式是另一套寫法,樣式會被flexible轉換,就會破壞框架的樣式。
如果在.vue文件style中的某一行代碼不希望被轉成rem,只要在后面寫上注釋 /* no*/就可以了。
3、vue-touch
官網:https://github.com/vuejs/vue-touch/tree/next
介紹:vue-touch其實封裝了 hammer.js的方法,針對觸屏的6大事件進行監聽。
使用方法:
- 安裝vue-touch:
npm install vue-touch@next
- 嵌入vue-touch:
在vue入口文件main.js中將其注冊為全局組件:
var VueTouch = require('vue-touch') Vue.use(VueTouch, {name: 'v-touch'})
使用實例:
<v-touch v-on:swipeleft="onSwipeLeft(data)">Swipe me!</v-touch> //左划 默認渲染為div data為參數
<v-touch tag="a" v-on:tap="onTap">Tap me!</v-touch> //點擊 渲染為一個a標簽
<v-touch tag="p" v-on:tap="onTap">Tap me!</v-touch> //點擊 渲染為p標簽
常用的事件有:swiper(滑動事件)、tap(短時間內的點擊事件)、press(事件大於tap的按壓事件)
api及相關的事件:
事件說明:
(1)、pan,觸屏中的拖動事件,在指定的dom區域內,一個手指放下並移動事件
事件類型有:pan, panstart, panmove, panend, pancancel,
panleft, panright, panup, pandown;
使用方法為:v-on:panstart="callback";
(2)、Swipe:滑動事件,在指定的dom區域內,一個手指快速的在觸屏上滑動。
事件類型有:swipe, swipeleft, swiperight,
swipeup, swipedown
使用方法為:v-on:swipeleft="callback";
(3)、Tap:在指定的dom區域內,一個手指輕拍或點擊時觸發該事件(類似PC端的click)。該事件最大點擊時間為250毫秒,如果超過250毫秒則按Press事件進行處理。
事件類型:tap
使用方法:v-on:tap="callback"
(4)、Press:在指定的dom區域內觸屏版本的點擊事件,這個事件相當於PC端的Click事件,該不能包含任何的移動,最小按壓時間為500毫秒,常用於我們在手機上用的“復制、粘貼”等功能。該事件分別對以下事件進行監聽並處理:
事件類型:press, pressup
使用方法:v-on:press = "callback"
(5)、Rotate事件:在指定的dom區域內,當兩個手指或更多手指成圓型旋轉時觸發(就像兩個手指擰螺絲一樣)。該事件分別對以下事件進行監聽並處理
事件類型:rotate, rotatestart, rotatemove, rotateend, rotatecancel,
使用方法:v-on:rotate = "callback"
(6)、Pinch:在指定的dom區域內,兩個手指(默認為兩個手指,多指觸控需要單獨設置)或多個手指相對(越來越近)移動或相向(越來越遠)移動時事件。該事件事以分別對以下事件進行監聽並處理:
Pinchstart:多點觸控開始、Pinchmove:多點觸控過程、Pinchend:多點觸控結束、Pinchcancel:多點觸控取消、Pinchin:多點觸控時兩手指距離越來越近、 Pinchout:多點觸控時兩手指距離越來越遠
注意事項:
(1)、注意:vue-touch 使用的是2.0.0版本 需要與vue2.0.0兼容;
應用實例:
(2)、通過手勢滑動,進行頁面的切換,如:
swiperleft: function () { this.$router.push({'path':'/queuehistory'}); },
4、vee-validate
- vee-validate介紹:
vee-validate為適用於vue項目中表單驗證插件.引入vee-validate,會更加方便我們進行表單驗證。 官方網址.
- 安裝vee-validate
npm install vee-validate@next --save
注意:@next,不然是Vue1.0版本
- main.js里引用vee-validate插件
import Vue from 'vue' import VeeValidate,{ Validator } from 'vee-validate' import zh_CN from 'vee-validate/dist/locale/zh_CN' //引入中文包,提示信息可以以中文形式顯示 Validator.addLocale(CN) // 設置提示信息中文方式顯示 Vue.use(VeeValidate, { locale: 'zh_CN'})
- 擴展自定義驗證規則
Validator.extend('phone', { messages:{ zh_CN: field => '請輸入正確手機號' }, validate: value => { return /^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/.test(value) } }); Validator.extend('isCard', { messages: { zh_CN: field => '請輸入正確身份證號' }, validate: value => { return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(value) } })
- 自帶規則的中文設置
const dictionary = { zh_CN: { messages: { required: (val) => { let msg = '' switch (val) { case 'ownerPhone': msg = '手機號' break } msg = msg + '不能為空哦' return msg }, numeric: (val) => { let msg = '' switch (val) { case 'houseShi': msg = '居室' break } msg = msg + '只能為數字' return msg } } }} Validator.updateDictionary(dictionary)
- 組件中使用
<form class="form" autocomplete="off" @submit.prevent="validateBeforeSubmit"> <div class="form-item"> <input type="number" placeholder="請輸入你的手機號" v-model="params.ownerPhone" v-validate="'required|ownerPhone'" name="ownerPhone"> <span v-show="errors.has('ownerPhone')" class="help is-danger"> {{ errors.first('ownerPhone') }} </span> </div> <button class="form-btn bg-blue" type="submit">登錄</button> </form>
5、better-scroll
- better-scroll介紹:
- 使用方法
安裝方法
npm install --save better-scroll;
起步
<div class="wrapper"> <ul class="content"> <li>...</li> <li>...</li> ... </ul> <!-- 這里可以放一些其它的 DOM,但不會影響滾動 --> </div>
上面的代碼中 better-scroll 是作用在外層 wrapper 容器上的,滾動的部分是 content 元素。這里要注意的是,better-scroll 只處理容器(wrapper)的第一個子元素(content)的滾動,其它的元素都會被忽略。
import BScroll from 'better-scroll' let wrapper = document.querySelector('.wrapper') let scroll = new BScroll(wrapper)
結合接口下拉刷新加載更多數據

export default { methods:{ async getMyBillList() { const res = await getMyBillList(reqData); if (res.status.code == "200") { this._houseScroll(); // 結合接口初始化scroll數據 }else{ console.log("接口調用失敗~"); } }, _houseScroll(){ this.$nextTick(() => { if (!this.houseScroll) { let wrapper = document.querySelector('.wrapper'); // scroll容器 // new Bscroll(),初始化容器; this.houseScroll = new Bscroll(wrapper,{ scrollY: true, probeType: 3, click: true, pullUpLoad: { threshold: -100 // 在上拉到超過底部 20px 時,觸發 pullingUp 事件 } } ); // 初始化上拉刷新加載更多方法 this.houseScroll.on("pullingUp", () => { this.pageNo++; if (this.totalPage >= this.pageNo) { this.pageNo++; // 通過pageNo增加,加載第二頁的數據 this.getMyBillList(); this.loading = true; } else { this.loading = false; this.loadingOver = true; } }); } else { this.houseScroll.finishPullUp(); this.houseScroll.refresh(); } }); } } }
6、fastclick插件:解決移動端click 300ms延遲
移動端項目中,在某些機型某些瀏覽器下,存在click事件300ms延遲的問題,影響用戶滿意度。原因是:從點擊屏幕上的元素到觸發元素的 click 事件,移動瀏覽器會有大約 300 毫秒的等待時間,因為它想看看你是不是要進行雙擊(double tap)操作。
vue項目中,可以通過引入fastclick第三方依賴包來解決。
安裝方法:
npm install --save fastclick
使用方法:
在main.js中
import fastclick from 'fastclick' fastclick.attach(document.body)
也可以直接下載fastclick.js,在相應頁面直接引用。
7、手機前端開發調試利器 – vConsole
移動端項目,由於在移動端無法打開控制台,所以無法像pc端chrome控制台那樣直觀查看console信息;不過我們可以使用
vConsole插件
進行調試。
使用方法如下:
安裝vConsole:
npm install vconsole --save-dev
在main.js中引用並實例化:
import VConsole from 'vconsole'; const vConsole = new VConsole(); // 不使用的時候,可以將這句屏蔽掉;
此時可以使用console.log
原理:改寫了console.log,重寫了實現,用vConsole代理
結果就會出現如圖 浮動的按鈕,點開之后,就可以看到里面的console信息了;
8、webpack之proxyTable設置跨域
在平時項目的開發環境中,經常會遇到跨域的問題,尤其是使用vue-cli這種腳手架工具開發時,由於項目本身啟動本地服務是需要占用一個端口的,所以必然會產生跨域的問題。在使用webpack做構建工具的項目中,使用proxyTable代理實現跨域是一種比較方便的選擇。
proxyTable相關配置及使用說明:
當我們用vue-cli構建項目時,需要在config/index.js文件中,找到dev對象下proxyTable對象進行跨域設置,配置如下:
dev: { env: require('./dev.env'), port: 8080, autoOpenBrowser: true, assetsSubDirectory: 'static', assetsPublicPath: '/', cssSourceMap: false, proxyTable: { '/api': { target: 'http://www.abc.com', //目標接口域名 changeOrigin: true, //是否跨域 secure: false, // 允許https請求 pathRewrite: { '^/api': '/api' //重寫接口 } } }
proxyTable配置的意思為:使用字符串"/api"來代替目標接口域名;如果接口地址為"user/getUserInfo",我們可以在所有的接口地址前面加上"/api/"用於設置代理;如:
'http://localhost:8080/api/user/getUserInfo' ===> 'http://www.abc.com/api/user/getUserInfo'
如果你不想每次請求地址中都帶有"/api/",則可以設置
pathRewrite: { '^/api': '' // 后面可以使重寫的新路徑,一般不做更改 }
表現結果為:
'http://localhost:8080/api/user/getUserInfo' ===> 'http://www.abc.com/user/getUserInfo'
另外一種情況是,我們不需要在每個接口地址前添加"/api/",只需要用接口本身的地址,不需要重新路徑即可。如果接口為:"/v2/cotton/get_app_list",使用"/v2"做代理;如下:
dev: { proxyTable: { '/v2': { target: 'http://www.abc.com', //目標接口域名 changeOrigin: true, //是否跨域 secure: false, // 允許https請求 // 這里去掉了重新設置新路徑,因為接口地址本身就是以"/v2/"開頭的; } }
'http://localhost:8080/v2/cotton/get_app_list' ===> 'http://www.abc.com/v2/cotton/get_app_list' // http://localhost:8080/v2表示http://www.abc.com
默認情況下,不接受運行在 HTTPS 上,且使用了無效證書的后端服務器。如果你想要接受,修改配置如下:
proxy: { "/api": { target: "https://www.abc.com", secure: false } }
9、vue組件之間通信
- 父向子傳遞數據通過props
/**父組件代碼:**/ <template> <header-box :title="text"></header-box> </template> <script> import HeaderBox from './header' export default { name: 'index', components: { HeaderBox }, data () { return { text: '首頁' } } } </script>
/**子組件代碼**/ <template> <header> {{thisTitleTxt}} </header> </template> <script> export default { name: 'headerbox', props: { text: String }, data () { return { thisTitleTxt: this.text } } } </script>
- 子向父傳遞數據
子組件向父組件傳遞分為兩種類型。
1、子組件改變父組件傳遞的props(你會發現通過props中的Object類型參數傳輸數據,可以通過子組件改變數據內容。這種方式是可行的,但是不推薦使用,因為官方定義prop是單向綁定);
2、通過$on和$emit;即子組件中通過$emit()來觸發事件;父組件中通過依附在組價元素上的:on方法來響應事件。

*通過$on,$emit* **父組件代碼** <template> <div id="counter-event-example"> <p>{{ total }}</p> <!--父組件中通過v-on:key="function"來觸發方法的執行--> <button-counter v-on:increment="incrementTotal"></button-counter> </div> </template> <script> import ButtonCounter from './buttonCounter' export default { name: 'index', components: { 'button-conuter': ButtonCounter }, data () { return { total: 0 } }, methods: { incrementTotal () { this.total++ } } } </script> **子組件代碼** <template> <button @click="incrementCounter">{{counter}}</button> </template> <script> export default { name: 'button-counter', data () { return { counter: 0 } }, metheds: { incrementCounter () { this.$emit('increment');// 子組件中通過this.$emit('key',value)觸發事件信號 this.counter++ } } } </script>
- 非父子組件傳遞數據;
通過使用一個空的Vue實例作為中央事件總線。
**main.js** let bus = new Vue() Vue.prototype.bus = bus;
相鄰組件1,通過$emit()傳遞數據
this.bus.$emit("toChangeTitle","首頁");
相鄰組件2,通過$on()接收數據
mounted(){ this.bus.$on('toChangeTitle', function (title) { console.log(title) }) }
10、ref特性的使用
ref
被用來給元素或子組件注冊引用信息。引用信息將會注冊在父組件的 $refs
對象上。
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子組件上,引用就指向組件實例:
<div id="app"> <input type="text" ref="input1" v-model="name"/> <button @click="add">添加</button> <!-- `vm.$refs.child` will be the child component instance --> <child-component ref="child"></child-component> </div> <script> export default{ data(){ return { name:"xiaoming" } }, created(){ this.$nextTick(()=>{ console.log(this.$refs.input1.value); }); }, methods:{ add(){ this.$refs.input1.value = "22"; //this.$refs.input1 減少獲取dom節點的消耗 } } } </script>
當 v-for
用於元素或組件的時候,引用信息將是包含 DOM 節點或組件實例的數組。
關於 ref 注冊時間的重要說明:因為 ref 本身是作為渲染結果被創建的,在初始渲染的時候你不能訪問它們 - 它們還不存在!$refs
也不是響應式的,因此你不應該試圖用它在模板中做數據綁定。
通過在引用的子組件上使用ref屬性實現父組件調用子組件的方法及屬性
在父組件中引用子組件並定義ref
<v-food ref="selectfood"></v-food>
調用定義在子組件中的方法show
this.$refs.selectfood.show();//同時也可以調用子組件中的屬性。
11、vue中setTimeout的使用
在vue中使用setTimeout或者setInterval,如果按照在原來js的中方法,如
setTimeout(function(){ this.isFlag = true; },3000);
會發現data中定義的變量isFlag是獲取不到的;解決方法如下:
- 用setTimeout通過es6語法,setInterval也是一樣
import { setTimeout } from "timers"; <script> export default{ data(){ return { time:"", isFlag:false } }, methods:{ add(){ clearTimeout(this.time); this.time = setTimeout(() =>{ this.isFlag = true; },2000) } } } </script>
- 定義外部self來代替全局this
methods:{ add(){ let self = this; clearTimeout(this.time); this.time = setTimeout(function(){ self.isFlag = true; },2000) } }
我們會發現利用例子的第一種方法,使用this來獲取變量,會報錯。這就是老生常談的javaScript 的this 的問題。
因為用的一個function(){} 這里的 獨立的作用域 this指向了全局(這里是window)而且window里沒有myFunc這個函數,所報了錯。
使用es6的->寫法,this繼承外部對象,this指向為vue實例,即(new Vue);
12、監聽鼠標滾動事件,實現頭部懸浮效果
$nextTick 是在下次 DOM 更新循環結束之后執行延遲回調,鼠標滾動事件需要通過window.addEventListener("scroll",'')進行監聽。
<script> mounted(){ // 監聽滾動事件 this.$nextTick(function () { window.addEventListener('scroll', this.needToTop); //滾動事件監聽 }); }, methods:{ needToTop(){ let curHeight = document.documentElement.scrollTop || document.body.scrollTop; // 滾動條距離頂部的距離 let bgareaHeight = this.$refs["bgarea"].offsetHeight; // 背景總高度 let opacity = curHeight/bgareaHeight; this.$refs["title"].style.background = "rgba(255, 255, 255, "+opacity+")"; this.$refs["title"].style.boxShadow = "0 0 .27rem rgba(204, 204, 204, "+opacity+")"; } } </script>
13、vue上傳圖像
通過new FormData(),創建form對象,通過append向form對象添加數據。
html代碼如下:
<div class="txarea"> <input type="file" class="txfile" name="file" id="upimg" accept="image/*" @change="fileChange($event)"> <p class="tx" @click="chooseType">點擊上傳頭像</p> </div> <script> export default{ methods:{ // 獲取用戶圖像 chooseType() { document.getElementById('upimg').click(); }, fileChange(e) { let file = e.target.files[0]; let param = new FormData(); //創建form對象 param.append('file',file,file.name);//通過append向form對象添加數據 let config = { headers:{'Content-Type':'multipart/form-data'} //添加請求頭 }; this.axios.post(uploadUrl,param,config) .then(response=>{ // 已經獲取到圖片地址,再調接口,保存到數據庫即可; let reqData = { phone: this.loginInfo.phone, pic:response.data.url // 大圖地址 } this.setUserInfo(reqData); }) }, setUserInfo(){ // 保存用戶圖像 ... } } } </script>
14、vue,@click="event()",添加()與不添加()的區別
應該是 Vue 對函數調用表達式額外用了一個函數做了層包裝。
加與不加括號的區別在於事件對象參數 event 的處理。
不加括號時,函數第一個參數默認為 event;加了括號后,需要手動傳入 $event 才能獲得事件對象。
<template> <div class="btn-item"> <button class="btn btn-success" @click="sure($event)">確定</button> <button class="btn btn-default" @click="quit">取消</button> </div> </template> <script> export default{ name:'test', data(){ return { } }, methods:{ sure(e){ console.log(e.target); }, quit(e){ console.log(e.target); } } } </script>
項目實踐:基於vue2.0 +vuex+ element-ui后台管理系統
后面會更新第二篇文章:
- VUX - Vue 移動端 UI 組件庫的使用;
- vuex:vue狀態管理工具詳細入門;
- 百度地圖api在vue項目中的使用:
- vue2如何給地圖添加房源覆蓋物;
- 如何給地圖添加自定義定位控件並更換控件的圖標;
- 幾個常用的api(地圖縮放,拖拽,獲取當前位置)等功能的實現;
- 微信api在vue項目中的使用:
- vue2實現微信分享坑點和經驗 ;
- vue2實現微信支付坑點和經驗;
- fetch封裝接口的統一管理;