vue for webapp 中的總結&&填坑
歷時三個星期,在教程和文件的抽絲剝繭中敲完,中間體會以此為記
本專案使用的vue-cli腳手架,安裝過程簡單交代, 如想詳細瞭解,請參考官方文件
1.新建工程檔案vue-for-sellapp
2.cd vue-for-sellapp
3.npm install vue-cli
4.vue init webpack //專案基於webpack模板
5.npm install //安裝依賴
6.npm run dev //啟動伺服器,預設埠8080
現在挑幾個重點難點說一說
vuejs將多個元件組合為一個應用,卻沒有解決不同頁面的切換問題,也就是說同一個頁面區域內,可能需要根據使用者的手動切換進行不同的渲染,展示不同的內容。
vue-router提供了很好的路由指向功能,看如下程式碼
<div class="tab"> <div class="tab-item"> <router-link to="/goods">商品</router-link> </div> <div class="tab-item"> <router-link to="/ratings">評論</router-link> </div> <div class="tab-item"> <router-link to="/seller">商家</router-link> </div> </div> <router-view :seller="seller"></router-view> <!--路由匹配到的元件將自此處渲染 -->
程式碼中的<router-link to=""></router-link>標籤提供了路由指向功能,當我們點選“商品”時便會把定義好的goods元件渲染到
<router-view :seller="seller"></router-view>
之中,同時將seller物件傳入到匹配到的元件中(這裡稱其為子元件 ),在此子元件中通過props接收到父元件傳入的seller物件,一個很巧妙的資料流動方式。
<router-link to="/goods">商品</router-link>預設的渲染結果是<a href="/goods">商品<a>
當我們點選了“商品”時,
<router-link>
對應的路由匹配成功,將自動設定 class 屬性值 .router-link-active
,我們便可通過此類名為點選事件新增樣式。到此為止,我們都在講vue-router的原理和使用,那麼它是如何引入到專案中的呢,我們看專案的入口檔案main.js
import Vue from 'vue';
import VueRouter from 'vue-router'; //首先引入依賴,命名為VueRouter
import VueResource from 'vue-resource';
import App from './App.vue';
import goods from './components/goods/goods.vue';
import ratings from './components/ratings/ratings.vue';
import seller from './components/seller/seller.vue';
Vue.use(VueRouter);//外掛註冊
Vue.use(VueResource);
const router = new VueRouter({
routes:[
{
path:'/goods',//為每個元件定義路由路徑,使用此路徑便可以呼叫對應元件
component:goods
},
{
path:'/ratings',
component:ratings
},
{
path:'/seller',
component:seller
}
]
});
let sellapp=new Vue({
el:'#app',
template: '<App/>',
components:{ App },
router //為例項注入路由,從而讓整個應用都有路由功能
})
在這裡有的開發者對Vue.use()函式抱有很多幻想,這裡推薦一篇文章Vue.use原始碼分析至於vue-resource先不做討論
二、生命週期鉤子
生命週期分八個狀態對應八個函式,自始至終分別是
1.beforeCreate()
2.created()-------例項已經被建立完成並呼叫,資料觀測(data observer),屬性和方法的運算,watch/event事件回撥已準備就緒,但是例項尚未掛載,沒有進行DOM樹構建 和渲染
3.beforeMount()
4.mounted()-------el
被新建立的vm.$el
替換,元件掛載成功
5.beforeUpdate()-------資料更新時呼叫,此時還沒發生DOM重新渲染以及打補丁,可以在這個鉤子中進一步更改狀態,這不會觸發附加的重渲染過程
6.updated()-------資料更改導致DOM重新渲染和打補丁,在這之後呼叫該鉤子,當這個鉤子被呼叫時,元件DOM已經更新,所以可以執行依賴更新後的DOM節點的操作
7.beforeDestroy()
8.destroyed()
基於本專案所涉及,這裡只提一下vm.$nextTick()
看如下程式碼
_initScroll() {
this.$nextTick(() => {
if(!this.scroll) {
this.scroll = new BScroll(this.$refs.seller, {
click: true
});
} else {
this.scroll.refresh();
}
})
}
將回調延遲到下次 DOM 更新迴圈之後執行。在修改資料之後立即使用它,然後等待 DOM 更新。它跟全域性方法 Vue.nextTick 一樣,不同的是回撥的this
自動繫結到呼叫它的例項上。此處有坑,看下面程式碼(seller.vue元件中)
watch: {
'seller' () {
this._initScroll();
//console.log("watch執行了");
//console.log(this.$refs.info);
//console.log(this.seller.infos);
//this._initPics();
}
},
mounted() {
this._initScroll();
//console.log("mounted執行了");
//console.log(this.$refs.info);
//console.log(this.seller.infos);
//this._initPics();
}
_initScroll()
_initScroll() {
this.$nextTick(() => {
if(!this.scroll) {
this.scroll = new BScroll(this.$refs.seller, {
click: true
});
} else {
this.scroll.refresh();
}
})
}
很明顯,我要在seller元件中實現頁面滾動,為什麼需要mounted鉤子以及watch監視seller物件共用呢,寶寶心裡苦啊,原本以為vue生命週期中mounted鉤子呼叫階段頁面DOM早已構建渲染好,直接滑動便可,確實,我在主頁面http://localhost:8080/#/到點選進入http://localhost:8080/#/seller中確實實現了seller頁的滾動,可當我再次重新整理seller頁面(http://localhost:8080/#/seller)時,頁面又不能滾動了……
檢視控制檯輸出,發現this.seller.infos獲取不到,也就是seller物件並沒有傳進來,但是this.$refs.info卻獲取到了,不明白為什麼seller物件得不到頁面資料渲染卻成功了。
然後經過一番糾結困惱,我添加了seller物件監視,在監視到seller物件變化時,再次呼叫_initScroll(),如此這般,問題竟然奇蹟般解決了,不管是seller頁面重新整理還是從主頁面進入seller頁,滾動都沒問題,我嘗試將this.$nextTick方法棄用,發現又不行了……
總結一下:重新整理seller頁面時,seller物件非同步獲取,在還沒有獲取成功便執行了_initScroll(),此時頁面依賴seller物件提供的資料撐開,子元素沒有超出父元素的界限,自然不會觸發滾動,而使用watch監控seller變化,在seller變化完成後又執行_initSrcoll(),便可以觸發滾動。
四、父子元件通訊
我們知道子元件想獲取父元件的物件,可以用props進行傳遞,那麼父元件要獲取子元件傳遞的資訊該如何實現呢??
本專案為例,在ratings元件中嵌入了ratingselect子元件,而子元件獲取使用者的點選資訊要傳遞到父元件進行條件展示,比如客戶點選了“滿意”按鈕,那麼父元件要響應展示評論中好評的部分。
看下面程式碼
<div class="rating-type">
<span @click="select(2,$event)" class="block positive" :class="{'active':selectType===2}">{{desc.all}}<span
class="count">{{ratings.length}}</span></span>
<span @click="select(0,$event)" class="block positive" :class="{'active':selectType===0}">{{desc.positive}}<span
class="count">{{positives.length}}</span></span>
<span @click="select(1,$event)" class="block negative" :class="{'active':selectType===1}">{{desc.negative}}<span
class="count">{{negatives.length}}</span></span>
</div>
select方法
select(type, event) {
if(!event._constructed) {
return;
}
this.$emit('select', type);
}
vue為我們提供了$emit方法,將type繫結到指定的方法(第一個引數指定方法名)上,在這裡是select
好了,我們來看父元件如何拿到select方法。
<ratingselect :select-type="selectType" :only-content="onlyContent" :ratings="ratings" @select="select" @toggle="toggle"></ratingselect>
很清楚,在ratingselect元件掛載到父元件ratings時就已經通過v-on傳了進來,@select便是將子元件的select方法傳到父元件,後面的字串便是在父元件中對應的函式名,這裡還是用select。
最後,看一下在父元件中的函式使用
select(type){
this.selectType = type;
this.$nextTick(() => {
this.scroll.refresh();
});
}
五、web儲存
六、解析url
專案在部署使用過程中,難免遇到與個人資訊繫結的東西,比如id為1234的使用者點選收藏後,再次重新整理http://localhost:8080/?id=1234#/seller,則依然顯示已收藏,這就需要計算機得到使用者id,並且快取相關資訊,再次重新整理後讀取快取
那麼如何從URL中得到使用者資訊呢
七、初涉Express框架
在本專案中express來獲取data.json中的資料,並向客戶端傳送JSON響應
我已在另一篇部落格比較細緻地介紹了Express的基本原理和使用方法,請參見——Express框架學習筆記
未完待續……………………………………………………