1. 程式人生 > >vue for webapp 中的總結&&填坑

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框架學習筆記

未完待續……………………………………………………