--javascript
項目中會用到的插件 vue-router vue-resourcecss
打包工具 webpackhtml
依賴環境 node.js前端
# 全局安裝 vue-clivue
$ npm install -g vue-cli # 建立一個基於 "webpack" 模板的新項目 $ vue init webpack my-project # 安裝依賴,走你 $ cd my-project $ npm install $ npm run dev
文件解釋:java
build中配置了webpack的基本配置、開發環境配置、生產環境配置node
config中配置了路徑端口值等webpack
node_modules爲依賴的模塊git
src放置組件和入口文件github
static放置靜態資源文件
index.html文件入口
webpack中的一些解釋:
new HtmlWebpackPlugin 這個插件的做用是把output輸出的文件自動插入到html裏
這裏不使用elint檢查代碼
這裏使用vue-router 中文基本用法可參見http://router.vuejs.org/zh-cn...
把原來腳手架中的new Vue換成了路由實現,最容易忘記的一點是Vue.use(VueRouter);
這裏的Vue.extend()暫時先定義兩個臨時的組件,main.vue爲入口文件,組件內要添加路由視圖標籤<router-view></router-view>
這裏的router.start(app,"#app")的app是require進來main,'#app'是添加從index.html的id爲app入口
如今的效果是:
-this is bar 上面那部分是main.vue裏面的,
-this is bar 則是有router-view渲染出來的
app中要切換多個路由爲了避免代碼耦合將map映射部分提取到一個router.js文件中
這裏要後續要引用zepto開發,因此這裏要在webpack.base.conf.js中作一個配置
externals: {
'zepto': 'Zepto' },
*上截圖解釋這個參數,因此要加html中加如zepto的連接,而後在其餘地方就能夠引用了*
3.只是簡單地把組件和映射放到router.js中,而後在app.js中傳入router
router.js
app.js增長的代碼
如今頁面仍是和以前同樣沒有變化,基本框架和路由搭建完成,而後就能夠開始封裝組件
1.app的主頁底部通常都有幾個tab鍵是固定不變的,這裏實現四個tab鍵分別是首頁,發現,通知,我 2.這裏使用mobile sui搭建ui,在main.vue<style>中引用sui樣式
@import './assets/css/sm.css'; @import './assets/css/sm-extend.min.css';
這樣已經能呈現一個底部導航,可是不太符合vue組件化的概念,畢竟重複了四次的tab代碼,全部這裏要用slot進行內容分發
3.這裏要理解slot元素,先上一張官方的解釋
<slot> 就是外部調用時,標籤中的內容。若是外部調用時沒有提供內容的話,那麼它就會使用本身默認提供的內容,很是方便。
-這個字面意思確實難以理解,用代碼解釋 -首先定義Bar.vue組件替代最外層的nav
而後在main.vue import 進來引用
原來的nav標籤就會變成這樣寫
先看如今的效果
一切正常,可是若是把Bar.vue中的slot註釋,就沒有這些導航圖標了,因此我能夠理解爲使用了slot能夠把不在Bar.vue的template中的代碼引進來,不使用就直接使用Bar.vue的template模板了
如今能夠把裏面的item元素也弄成一個BarItem.vue組件
這裏要知道一個新的指令v-link和它的activeClass配合
v-link 是一個用來讓用戶在 vue-router 應用的不一樣路徑間跳轉的指令。http://router.vuejs.org/zh-cn... 詳情看這裏
先上代碼BarItem.vue
script中的props是在main.vue傳進來的參數,v-link中的replcace:true 是用了router.replace()而不是router.go()也就是不能後退(首頁標籤頁切換就不讓用戶有後退的功能了),activeClass是當路由激活時加上的類
main.vue如今的代碼
對了,記得把BarItem.vue引進來喔
如今的效果仍是像以前同樣,可是已經實現組件化
新建search.vue、message.vue、me.vue、home.vue,而後在router.js中作相應的配置
這裏動態組件載入就是常說的懶加載組件
當你在使用 Webpack 或者 Browserify 時,在基於異步組件編寫的 Vue 項目時,也能夠較爲容易的實現惰性加載組件。再也不是以前所述的直接引用一個組件,如今須要像下面這樣經過定義一個函數返回一個組件:
resolve這個參數有點難理解,實際就是用異步加載,用AMD風格的寫法是
require(['./MyComponent.vue'], function (MyComponent) { // code here runs after MyComponent.vue is asynchronously loaded .})
五個路由都寫好就能夠隨意切換tab了
想要達到這種效果
homeTab這部分也是能夠提取出組件做爲各個tab的頭部
贊一下vue的錯誤提示,一開始死活顯示不了,這錯誤提示仍是很明顯的
用組件記得在js components中註冊
還有這個提示,註冊了變量沒
這裏的ui用的是sui,包括下拉刷新也是用sui的組件,詳情:http://http://m.sui.taobao.or...
下拉刷新會有dom元素的操做,不能用jq的思想,因此要用到自定義指令
自定義指令提供一種機制將數據的變化映射爲 DOM 行爲
pullToRefresh.js
用到的鉤子函數:
bind:只調用一次,在指令第一次綁定到元素上時調用。
unbind:只調用一次,在指令從元素上解綁時調用。
在註冊以後,即可以在 Vue.js 模板中這樣用(記着添加前綴 v-),看成爲屬性指令的時候
用到的指令實例屬性:
el: 指令綁定的元素。
vm: 擁有該指令的上下文 ViewModel。
expression: 指令的表達式,不包括參數和過濾器。
params:自定義指令能夠接收一個 params 數組,指定一個特性列表,Vue 編譯器將自動提取綁定元素的這些特性。this.params[key]會自動保持更新。
data-ptr-distance="55"能夠配置下拉刷新的下拉距離,sui的配置
在app.js中註冊自定義指令
import pullToRefresh from './directives/pullToRefresh' //directive Vue.directive('pullToRefresh', pullToRefresh);
自定義指令完成
而後是要將這部分的ui封裝成組件放在兩個tab裏
就是封裝官網上的這段代碼
-前面已經說過怎麼去拆分組件了,只要你以爲合理,子父組件之間能通訊想怎麼拆均可以,固然以複用爲原則,直接上我本身的拆分方式,能夠對比一下跟第二篇的源碼,都會同步到github,不管怎麼定義記得要在components裏面註冊--vue函數中經過this.$el來獲取當前元素
千萬要注意一個概念叫作片斷實例
就是模板中只有一個頂級元素,不然會對你下面獲取當前元素產生影響,若是你在函數中想要獲取當前元素用this.$el獲得的不是一個節點,而是一個空文本元素,那麼你就要去檢查你的模板是否是有問題了
這裏最重要的是把剛剛的指令引入進來了
前面有提到做爲屬性要加v-前綴
如今能夠去書寫你下拉刷新是要執行的函數了,在methods方法中定義
那個$.showIndicator的效果其實就是這個
以前有一點沒有提到,就是sui須要執行一個init()方法纔能有上面的效果,並且是在ready方法中init,這是基本配置,因此要在入口文件main.vue加個.page,不然會報找不到id的錯誤
如今的效果是下拉能夠增長一個.card,可是切換路由的時候再回到頁面就不見了。因此要綁一個變量存數據。今天這個自定義指令挺難理解的,先keep一份代碼吧
(3)中的狀況是不管在動態tab下拉刷新仍是在前端tab下拉刷新同時會增長dom元素
主要是由於這一句話,這裏的this是指向整個template的根目錄,這也正好能夠解釋片斷實例爲何獲取不到元素了
main.vue
那就必須是添加到當前指令下的.card-container,因此要獲取到當前指令元素,能夠在自定義指令中得到並傳參
PullToRefresh.js
如今能夠main.vue 中的函數中獲取這個參數,利用它獲取當前元素的.card-container
vue是爲數據而生的,不應過多的操做dom,而以前的全部刷新都是append了一次元素
爲了模擬有真實是的數據時的狀況,把將定義兩個數組將分別對應兩個tab裏面的數組task1,task2,並在每次下拉時push進去,這時候咱們就不在須要操做dom元素了,只須要關心data的變化
爲了讓存放在不一樣的數組中在自定義指令的元素上加入了這些屬性
而後在pullToRefresh.js中將它設置到自定義屬性中,固然要記得在params中傳入特性,(這裏我總感受我這方法有點麻煩,若是在指令中傳參我尚未明確,但願有知道的大神指點一二)
每次下拉函數都會push一個數組
html中用v-for輸出數組
基本的home.vue已經所有完成了
當我很開心的覺得結束了今天的任務的時候,我切換一下底部菜單,而後再回到home tab時,整我的都很差了,剛剛下拉的數據所有沒了,回到剛開始的頁面
我本想着要自定義方法來存儲,但是參考資料裏面是並不用這麼麻煩的,尋尋覓覓了好久好久,終於遇到了神奇的它---keep-alive
先來了解一下動態組件
當用戶關閉component時,將該component卸載,再次打開時從新加載。
這個項目裏在router-view標籤中加上keep-live就能夠緩存組件了
擴展:根據官方的這個案例,經過:is和keep-alive能夠實現隨意切換是否緩存這個組件
如今不管怎麼點tab鍵都能保留下拉刷新的那幾個內容了
前面step1到step8已經將首頁和基本菜單欄完成,如今先作我的中心頁也就是底部菜單中‘我’這個tab*
首頁點擊去看詳情和寫新動態加到列表中放到後面再完成
整體預覽
以前作過一個HeaderTab的組件,如今能夠拿來用了
- 若是你遇到底部切換頁面能夠正常顯示,可是直接刷新瀏覽器卻不起做用,那麼你看看是否是沒有$init()
第二部分是圖片,sui中1rem等於20px
第三部分是我的信息,爲了模擬之後從後臺獲取數據,將這部分抽離出來定義一個UserDetail組件並將數據存儲在一個數據中,這個數組存放在me.vue中
子父之間的通訊:雖然以前也有提到過,可是以前都是在父組件上傳遞一個字符串,當時的栗子是這樣的
而後在子組件的props中註冊status就能夠直接用了,可是今天要傳遞的是一個數組data 若是直接寫成data="userData" vue是不能識別你這個是字符串仍是變量數組的
因此這裏要用v-bind:user-data='userData',這裏還有一個坑,若是你寫的是v-bind:userData='userData'就會報錯了。
組件中的樣式我定義的比較隨便,直接用標籤來定義樣式,由於這裏加了scope只做用在當前組件,vue會自動處理加一串標記數字,這樣不再用爲命名擔憂了
第三部分的tab與第二部分相似,也是抽離一個組件,這裏定義數組將內容與結構分離,用v-for循環輸出結構,若是要改內容直接改數組,不用在一大堆的html結構裏面去找文字了
//這裏之因此數組套數組是由於考慮到sui的.row樣式結構須要 //path就是路由的路徑了,都要添加到router.js文件中 lists :[ [{ title:'動態', icon:'icon-app', path:'/me/moment' }, { title:'訪客', icon:'icon-friends', path:'/me/friends' }], [{ title:'文章', icon:'icon-menu', path:'/me/articles' }, { title:'最佳實現', icon:'icon-browser', path:'/me/practice' }], [{ title:'閱讀', icon:'icon-code', path:'/me/read' }, { title:'收藏列表', icon:'icon-star', path:'/me/love' }] ]
<user-refer v-bind:lists='lists'> </user-refer> <div v-for="list in lists" class="row"> <div class="col-50"> <a class="tab-item" v-link="{ path: list[0].path}"> <!-- 這裏不一樣於首頁的tab標籤切換,因此不須要replace這個參數,讓路由能夠後退 --> <span class="icon" v-bind:class="list[0].icon"></span><br> <span class="tab-label">{{list[0].title}}</span> </a> </div> <div class="col-50"> <a class="tab-item" v-link="{ path: list[1].path}"> <span class="icon" v-bind:class="list[1].icon"></span><br> <span class="tab-label">{{list[1].title}}</span> </a> </div> </div> </div>
第三部分的tab鍵點擊進去的詳情仍是用路由實現,下面這一部分能夠用組件封裝,路由不用加replace=true參數,返回按鈕加上我的中心的路由,詳細內容無非就是下拉列表,大體跟首頁同樣,能夠看step1-step8
將首頁的數據變爲動態獲取的
首先定義一個json文件,注意格式,不然解析不了會爲null,建議能夠把本身的json文件在線檢測一下
news.json
這個文件放在static/data,要在app.js中作相應的配置
import VueResource from 'vue-resource'
參數解釋:
proces.env.NODE_ENV 在vue-cli搭建的時候bulid文件裏面配置好的能夠去研究一下
Vue.http.options.emulateJSON = true;
If your web server can't handle requests encoded as application/json , you can enable the emulateJSON option. This will send the request as application/x-www-form-urlencoded MIME type, as if from an normal HTML form.--- 給你個眼神本身領悟吧,相信個人翻譯還不如本身百度,哈哈
而後使用$http去獲取數據,返回值response,利用$set設置 Vue 實例的屬性值,也就是以前的假數據task1
task1數據改變就會引發視圖的變化,如今效果是這樣的,那麼改變一下之前下拉push進去的假數據
先每次刷新都能獲取一次數據了,基本模擬了後端傳輸數據的效果
但願每一個列表都能點擊去看文章詳情,那麼要監聽一下click事件,在子組件中,找到CardCon.vue
<div class="card" v-on:click="goDetail"> <slot></slot> </div>
定義goDetail方法,而且使用dispatch冒泡的父組件,傳入當前列表的索引,方便獲取數據
methods:{
goDetail (){
this.$dispatch('GoDetailRouter', $(this.$el).index()) } }
$emit $dispatch $brocast
在父組件中的events中監聽子組件的事件,msg就是傳入的參數,利用路由go方法跳轉到詳情頁
events :{//監聽子組件 GoDetailRouter (msg){ router.go({ name: 'detail', params: { Lcontent:encodeURIComponent(this.$data.task1[msg].Lcontent) } }); } }
router.js
'/home/detail/:Lcontent': { name:'detail', component (resolve) { require(['./views/detail'], resolve) } }
這裏的Lcontent是傳入的參數,我這裏傳入的是詳情的文字,實際開發通常是傳一個id而後從後臺獲取相應的數據
增長detail.vue,要了解router鉤子函數才能瞭解下面這一段代碼
route: {
data: function (transition) { this.$set('Lcontent',decodeURIComponent(this.$route.params.Lcontent)); } }
因爲若是我在ready中去獲取參數,由於keep-alive將組件緩存因此只會執行一次,可是router的data切換鉤子會在每次路由切換的時候調用,保證了當前的參數是最新的