最近在用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()",新增()與不新增()的區別;
- H5,設定textarea高度隨文字輸入增高;
- vue,監聽滾動條滾動到最底部,載入下一頁資料;
cssrem
“cssrem.rootFontSize”: root font-size (unit: px), 預設為: 16;
“cssrem.fixedDigits”: px轉rem小數點最大長度,預設:6;
“cssrem.autoRemovePrefixZero”:自動移除0開頭的字首,預設:true;複製程式碼
專案中配置:
"cssrem.fixedDigits": 2,//px轉化為rem保留2位小數
"cssrem.rootFontSize":75//px轉化為rem基準複製程式碼
lib-flexible
- lib-flexible介紹:
lib-flexible為移動端彈性佈局適配解決方案。很多的大公司,如網易,淘寶等,都在用它作為移動端佈局。
- 使用方法:
npm install lib-flexible --save複製程式碼
import 'lib-flexible'複製程式碼
vue-touch
- vue-touch介紹:
vue-touch其實封裝了 hammer.js的方法,針對觸屏的6大事件進行監聽。官網。
- 使用方法:
npm install vue-touch@next複製程式碼
var VueTouch = require('vue-touch')
Vue.use(VueTouch, {name: 'v-touch'})複製程式碼
//左劃 預設渲染為div data為引數
<v-touch v-on:swipeleft="onSwipeLeft(data)">Swipe me!</v-touch>
//點選 渲染為一個a標籤
<v-touch tag="a" v-on:tap="onTap">Tap me!</v-touch>
//點選 渲染為p標籤
<v-touch tag="p" v-on:tap="onTap">Tap me!</v-touch>常用的事件有:swiper(滑動事件)、tap(短時間內的點選事件)、press(事件大於tap的按壓事件)複製程式碼
- api及相關的事件:
panleft, panright, panup, pandown;
使用方法為:v-on:panstart="callback";
swiperleft: function () {
this.$router.push({'path':'/queuehistory'});
}複製程式碼
vee-validate
- vee-validate介紹:
vee-validate為適用於vue專案中表單驗證外掛.引入vee-validate,會更加方便我們進行表單驗證。 官方網址.
- 安裝vee-validate
npm install vee-validate@next --save
複製程式碼
- 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>複製程式碼
better-scroll
- better-scroll介紹:
- 使用方法
安裝方法
npm install --save better-scroll;
複製程式碼
<div class="wrapper">
<ul class="content">
<li>...</li>
<li>...</li>
...
</ul>
<!-- 這裡可以放一些其它的 DOM,但不會影響滾動 -->
</div>複製程式碼
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();
}
});
}
}
}
複製程式碼
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,在相應頁面直接引用。
手機前端開發除錯利器 – 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資訊了;
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
}
}
複製程式碼
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;複製程式碼
this.bus.$emit("toChangeTitle","首頁");
複製程式碼
mounted(){
this.bus.$on('toChangeTitle', function (title) {
console.log(title)
})
}複製程式碼
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();//同時也可以呼叫子元件中的屬性
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);
監聽滑鼠滾動事件,實現頭部懸浮效果
$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>
複製程式碼
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>
複製程式碼
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>複製程式碼
H5,設定textarea高度隨文字輸入增高;
<template>
<textarea class="textArea" ref="textArea" placeholder="輸入正文" v-model="postList.content" @input="setPostContent"></textarea></template>
mounted(){
this.$nextTick(() => {
let textarea = document.querySelector('.textArea');
this.makeExpandingArea(textarea);
});
},
methods:{
setPostContent(){ // 設定正文內容
this.$refs.textArea.style.color = '#666666';
},
makeExpandingArea(el) {
var setStyle = function(el) {
el.style.height = 'auto';
el.style.height = el.scrollHeight + 'px';
}
var delayedResize = function(el) {
window.setTimeout(function() {
setStyle(el)
}, 0);
}
if (el.addEventListener) {
el.addEventListener('input',function() {
setStyle(el)},false);
setStyle(el)
} else if (el.attachEvent) {
el.attachEvent('onpropertychange',function() { setStyle(el)
});
setStyle(el)
}
if (window.VBArray && window.addEventListener) { //IE9
el.attachEvent("onkeydown",function() {
var key = window.event.keyCode;
if (key == 8 || key == 46) delayedResize(el); });
el.attachEvent("oncut",function() {
delayedResize(el);
}); //處理貼上
}
}
複製程式碼
vue,監聽滾動條滾動到最底部,載入下一頁資料;
mounted() { this.$nextTick(() => { document.getElementById("postDetail").onscroll = this.scrollBottom; }); }, methods:{ scrollBottom() { // 獲取 滾動高度 滾動距離 當前螢幕高度 let scrollHeight = document.getElementById("postDetail").scrollHeight, scrollTop = document.getElementById("postDetail").scrollTop, clientHeight = this.getClientHeight(); // 獲取離底部的距離 let bottomHeight = scrollHeight - scrollTop - clientHeight; // 傳送滾動到sendComments 元件 this.bottomHeight = scrollTop; // 如果距離底部小於5 請求資料 if (bottomHeight < 5) { this.pageNo++; if (this.totalPage >= this.pageNo) { // 說明還有更多的資料 this.loadings = true; this._getPostCommentList(); // 分頁獲取評論資料;回覆完評論,滾動條會自動到最底部,所以會載入第二頁的資料; } else { this.loadings = false; this.loadingOver = true; } } }} 複製程式碼
專案實踐:基於vue2.0 +vuex+ element-ui後臺管理系統
後面會更新第二篇文章:
第二篇文章如下:乾貨分享:vue2.0做移動端開發用到的相關外掛和經驗總結(2)
- VUX - Vue 移動端 UI 元件庫的使用;
- vue-lazyload :一個簡單易用的 Vue 圖片延遲載入外掛;
- vuex:vue狀態管理工具詳細入門;
- async/await:非同步神器來封裝介面請求檔案fetch.js;
- vue 專案中的迭代判斷技巧;
- vue 專案中常用的圖片引入方式;
- 微信api在vue專案中的使用:
- vue2實現微信分享坑點和經驗 ;
- vue2實現微信支付坑點和經驗;
百度地圖api在vue專案中的使用:
-
vue2.0專案中如何使用百度地圖api
-
vue2如何給地圖新增房源覆蓋物;
-
如何給地圖新增自定義定位控制元件並更換控制元件的圖示;
-
如何給地圖新增自定義當前位置定位標註
-
幾個常用的api(地圖縮放,拖拽,獲取當前位置)等功能的實現;
歡迎加入討論組,一起來學習用vue,vuex,element,express,mongodb來構建後臺管理系統;
一起來用專案實戰加深自己對知識的理解。