首先,慕課網提供的視頻是基於vue1.0的規範寫的,所以有一些地方在vue2.0下不能正常運行。雖然課程補充文件也提供了vue2.0的代碼,但多多少少也有一些問題。參考他人寫的代碼以及官方文檔,修改了部份內容,整個項目可以流暢運行,不會報錯。javascript
項目請移步個人github地址:https://github.com/gqbwoai2016/-VUE2.0-APP-。裏面內容還不是不少,之後會繼續豐富的。css
-------------------------------------------------------------------------------------------------------------------------------------------------html
廢話就這麼多,開始實質的內容吧:前端
涉及的工做有:由商家模塊入手,進行需求分析,利用腳手架工具搭建,mock數據,架構設計,代碼實現,自測以及編譯打包。本項目注重代碼規範:架構設計,組建抽象,模塊拆分,代碼風格統一,JS變量命名規範及CSS代碼規範。vue
所涉及的技術有:vue-cli腳手架工具;vue-resource與後端數據交互(相似AJAX);vue-router插件管理路由;第三方庫better-csroll;最大程度組件化(優勢:可維護性和複用性);localstorage;flex彈性佈局;java
實現的功能node
• Goods、Ratings、Seller組件視圖都可上下滾動 • 商品頁 點擊左側menu,右側list對應跳轉到相應位置 • 點擊list查看商品詳情頁,父子組件的通訊 • 評論內容夠能夠篩選查看 • 購物車組件,包括添加刪除商品及動效,購物控件與購物車組件之間非父子組件通訊,點擊購物車圖標,展現選擇的商品列表 • 商家實景圖片能夠左右滑動 • loaclStorage緩存商家信息(id、name)
0、用vue-cli腳手架工具搭建項目結構,有如下結構webpack
項目名稱 ->build ------------------------------------------ webpack配置相關文件 ->config ------------------------------------------ webpack配置相關文件 ->node_modules ------------------------------------------ 依賴代碼庫 ->src ------------------------------------------ 存放源碼 ->common ---- 通用的css和fonts ->components ---- Vue 組件 ->router ---- vue-router相關配置(linkActiveClass,routes註冊組件路由) ->build ---- webpack 的打包編譯配置文件 ->config ---- 一些配置項,好比咱們服務器訪問的端口配置等 ->dist ---- 項目通過 build 以後纔會生成 ->prod.server.js----模擬的服務器配置,用來運行dist裏面的文件,在config/index.js中,build對象中 添加一條端口設置port:9000, ->App.vue ---- 根組件,全部的子組件都將在這裏被引用 ->index.html ---- 整個項目的入口文件,將會引用咱們的根組件 App.vue ->main.js ---- 入口文件的 js 邏輯,在 webpack 打包以後將被注入到 index.html 中 ->static ------------------------------------------ 存放第三方靜態資源 ->.babelrc.JSON ------------------------------------------ babe的配製,用於從es6編譯至es5 ->.editorconfig ------------------------------------------ 編譯器配置 ->.eslintignore ------------------------------------------ 忽略語法檢查的目錄文件 ->.eslintrc.js ------------------------------------------ eslint的配置 ->.gitignore ------------------------------------------ git忽略的目錄或文件 ->index.html ------------------------------------------ 入口文件,項目編譯過程當中會自動插入其中 ->package.json ------------------------------------------ 配置文件,描述一個項目 ->README.md ------------------------------------------ 項目描述文件
全部項目文件放在src下,main.js爲入口文件,APP.vue爲整個頁面的vue,components存放組建文件,裏面有許多子目錄,子目錄中存放.vue文件及圖片等資源(知足組件化開發的就近維護)。common包含公共模塊資源(js,scss,fonts等)。 ios
一、 數據mockcss3
mock就是作假數據,這樣能夠便於先後端分離開發,前端不須要等後端作好數據來開發或者測試驗證
假數據data.json.實現:sell(項目總文件)->插入data.json,而後在build->webpack.dev.conf.js中寫數據接口,而後寫數據的路由。
坑1,最新版的vue中dev-server.js被替換成了webpack.dev.conf.js,修改時注意
二、reset
sell->static->css->reset.css,寫好後給index.html用link標籤引用這個文件
三、meta
對其設置viewport以規範顯示大小,縮放等移動端視口初始化。
四、header組件開發
a)使用vue-router實現點擊切換;在這裏,當前模塊樣式在vue-router中有個默認屬性linkActiveClass,在main.js對其配置後,在APP.vue中經過<vue-link to:"/goods">建立點擊部分以及<router-view>建立展現部分;
vue-router詳解:
路由,其實就是指向的意思。咱們頁面中全部內容都是組件化的,咱們只要把路徑和組件對應起來就能夠了,而後在頁面中把組件渲染出來。
頁面實現:定義了兩個標籤<router-link> 和<router-view>來對應點擊和顯示部分。<router-link> 就是定義頁面中點擊的部分,<router-view> 定義顯示部分,就是點擊後,區配的內容顯示在什麼地方。因此 <router-link> 還有一個很是重要的屬性 to,定義點擊以後,要到哪裏去, 如:<router-link to="/home">Home</router-link>
js中配置路由:首先定義route,由path,component組成,前者指路徑,後者指組件,以下所示,最後建立router管理路由。配置完成後,把router 實例注入到 vue 根實例中,就可使用路由了
const routes = [ { path: '/home', component: Home }, { path: '/about', component: About } ] //管理路由 const router = new VueRouter({ routes // routes: routes 的簡寫 }) //配置完成,注入到實例中 const app = new Vue({ router }).$mount('#app')//$mount爲手動掛載 //上面這個寫法也能夠改成 new Vue({ el:"#box", router });
注意:當首次進入頁面的時候,頁面中並無顯示任何內容。這是由於首次進入頁面時,它的路徑是 '/',咱們並無給這個路徑作相應的配置。在這裏使用重定向解決問題。
const routes = [ { path:"/home", component: home }, { path: "/about", component: about }, // 重定向 { path: '/', redirect: '/home' } ]
b)1像素實現:在APP端因爲dpr不一樣,展現會有問題,所以添加minxin.scss設置通用樣式後再經過base.scss使用@media 媒體查詢來分別設置不一樣dpr的scale控制樣式;
window.devicePixelRatio是設備上物理像素和設備獨立像素(device-independent pixels (dips))的比例。公式表示就是:window.devicePixelRatio = 物理像素 / dips
非視網膜屏幕的iphone上等於1,在視網膜屏幕的iphone上,屏幕物理像素640像素,獨立像素仍是320像素,所以等於2。
2x和3x圖是爲了適應不一樣dpr比例的,不一樣比例的顯示是不同的.2x就是普通的dpr爲1的屏幕使用的; 對於高清屏幕就是用3x,dpr爲2或者以上; 2x和3x就是尺寸的大小,2x的圖片比3x的小
c)滿減圖標在export default中create()內使用
classMap=['discount'...]
建立,在標籤中經過
:class="classMap[seller.supports[0].type]"
引用。
d)背景模糊:整個header組件中有模糊背景圖,可經過建立一個div而後絕對定位至相關位置,再用z-index=-1設置後,使用
filter:blur(15px)增長模糊效果。
e)css sticky footers模塊:簡而言之就是底部有一個固定圖標,只有移動至底部區域才展現,不然不顯示的一種佈局。
父級 position:fixed,內容設 爲padding-bottom:64px,頁腳相對定位,margin-top:-64px,clear:both
爲了保證兼容性,父級要清除浮動
坑2:新舊版vue-router不一樣,舊版支持router.map(),新版則使用const router=new VueRouter()直接在裏面寫便可
g)flex佈局:
意爲"彈性佈局",用來爲盒狀模型提供最大的靈活性。設爲Flex佈局之後,子元素的float
、clear
和vertical-align
屬性將失效。如下六個屬性設置在容器上:
flex-direction 容器內項目的排列方向(默認橫向排列)。可選值爲row(默認)沿水平主軸由左向右排列、row-reverse沿水平主軸由右向左排列、column沿垂直主軸右上到下和column-reverse。
flex-wrap 換行方式。nowrap(默認)不換行、wrap換行(第一行在上方)和wrap-reverse
flex-flow 以上兩個屬性的簡寫方式 .box { flex-flow: <flex-direction> || <flex-wrap>;}將上述兩種方法的值用||鏈接便可
justify-content 主軸上的對齊方式。主軸到底是哪一個軸要看屬性flex-direction的設置了flex-start:在主軸上由左或者上開始排列;flex-end:在主軸上由右或者下開始排列;center:在主軸上居中排列;space-between:在主軸上左右兩端或者上下兩端開始排列;space-around:每一個項目兩側的間隔相等。
align-items 交叉軸上如何對齊(縱軸對齊方式)flex-start頂對齊| flex-end底對齊 | center居中 | baseline文字基準線 | stretch撐開整個盒子
align-content 定義了多根軸線的對齊方式。若是項目只有一根軸線,該屬性不起做用。
設置在子元素的屬性也有六個:
order:項目排列順序,數值越小排名靠前,默認爲0;
flex-grow:項目放大比例,默認0;
flex-shrink:縮小比例,默認1;
flex-basis:計算主軸是否有多餘空間,默認auto,項目原本大小;
flex:是上面三個簡寫,默認0 1 auto;
align-self:容許單個項目有與其餘項目不同的對齊方式。
f)自適應佈局
左側寬度固定,右側寬度自適應
// 左側固定width:80px,右側自適應 parent: display:flex; child-left: flex:0 0 80px child-right: flex:1
五、goods模塊
a)採用better-scroll實現滾動,在package.json代表版本,使用npm安裝。BScroll接受兩個參數,第一個是DOM對象,第二個是方式,在method中寫方法,須要設置 click:true,不然移動端滑動無效。
注意:vue提供一種方法獲取DOM,在須要獲取地方添加ref="**",而後在js中經過this.$ref.**來引用;
DOM真正映射實在nextTick後,所以一些計算屬性應該寫在裏面,不然在頁面中無響應;
六、seller組件
a)商家實景圖片橫向滾動:
解決方案:每一個 li 要 display:inline-block,由於width不會自動撐開父級ul,因此須要將計算後的寬度賦值給ul的width,(每一張圖片的width+margin)*圖片數量-一個margin,由於最後一張圖片沒有margin,同時new BScroll裏面要設置scrollX: true, eventPassthrough: 'vertical', // 滾動方向橫向
b)打開seller頁面,沒法滾動
問題分析:出現這種現象是由於better-scroll插件是嚴格基於DOM的,數據是採用異步傳輸的,頁面剛打開,DOM並無被渲染,因此,要確保DOM渲染了,才能使用 better-scroll;解決方案:用到mounted鉤子函數,同時必須搭配this.$nextTick()
c)刷新後,沒法滾動
問題分析:出現這種狀況是由於mounted函數在整個生命週期中只會只行一次;解決方案:使用watch方法監控數據變化,並執行滾動函數 this._initScroll();this._initPicScroll();
d)緩存數據
使用window.localstorage保存舍設置緩存信息,封裝在store.js中
e)axios
在vue1.x的時候,vue的官方推薦HTTP請求工具是vue-resource,可是在vue2.0的時候將推薦工具改爲了axios。若是想像之前使用 vue-resource 那樣 this.$http.get 調用,要這樣定義:Vue.prototype.$http=axios;
經過 this.$http.get 來定義經過vue實例來發送get請求,而後經過then後面的回調函數將請求成功的數據接收,經過狀態碼來判斷是否成功以及複製給vue的數據對象。因爲這裏是用的mock數據(模擬後臺數據),因此用的模擬狀態碼。
const ERR_OK = 0;//表示沒有錯誤信息,即獲取數據成功 this.$http.get('/api/seller').then((response) => { response = response.data; if (response.errno === ERR_OK) { this.seller = Object.assign({}, this.seller, response.data); } });
vue-resource詳解:
vue-resource是Vue.js的一款插件,它能夠經過XMLHttpRequest或JSONP發起請求並處理響應。也就是說,$.ajax能作的事情,vue-resource插件同樣也能作到,並且vue-resource的API更爲簡潔。
優勢:體積小;支持主流瀏覽器;支持PromiseAPI和URI Templates;支持攔截器。
使用:
首先引入vue-resourec;而後發送請求便可
import VueResource from 'vue-resource'; Vue.use(VueResource); this.$http.get('/someUrl',jsonData).then(function(response){ //jsonData是傳給後端的數據 // 響應成功回調 }, function(response){ // 響應錯誤回調 });
下面給個實例,從a.txt取數據
<!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"> <script src="http://unpkg.com/vue/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/vue.resource/1.0.3/vue-resource.min.js"></script> <script type="text/javascript"> window.onload = function(){ var vm = new Vue({ el:'#box', data:{ msg:'Hello World!', }, methods:{ get:function(){ //發送get請求 this.$http.get('a.txt').then(function(res){ alert(res.body); },function(){ console.log('請求失敗處理'); }); } } }); } </script> </head> <body> <div id="box"> <input type="button" @click="get()" value="按鈕"> </div> </body> </html>
最新版Vue推薦使用axio,兩個功能相似,首先也要安裝而後引入,最後再使用:(注:他的註冊不能使用Vue.use()方法)
import axios from "axios"; //註冊 Vue.prototype.$axios = axios; //使用axios created:function(){ this.$axios.get("/seller",{"id":123}).then(res=>{ console.log(res.data); }); }
f)組件間通信
父傳子: props
// 父組件 <v-header :seller="seller"></v-header> // 子組件 header.vue props: { seller: { type: Object } }
子傳父: $emit 若是是子組件想傳遞數據給父組件,須要派發自定義事件,使用 $emit 派發,父組件使用v-on接收監控(v-on能夠簡寫成@)
// 子組件 RatingSelect.vue,派發自定義事件isContent,將this.onlyContent數據傳給父級 this.$emit('isContent', this.onlyContent); this.$emit('selRatings', this.selectType); // 父組件 foodInfo.vue 在子組件的模板標籤裏,使用v-on監控isContent傳過來的數據 <v-ratingselect @selRatings="filterRatings" @isContent="iscontent"></v-ratingselect>
非父子組件之間通訊: 1. 大型項目能夠用 Vue官方推薦的vuex;event bus: 利用一箇中間組件來做爲信息傳遞中介;
g)better-scroll
better-scroll是一個移動端滾動的解決方案,基於iscroll的重寫(多年沒人維護了,有不少bug;有些狀況是基於js實現的幀動畫,體驗差,bs基於css3等)
使用:首先應有一個父容器div,固定高度且overflow:hidden,給它設置bscroll,子元素高度由內容撐開。
<template> <div class="wrapper" ref="wrapper">//主div <ul class="content"> //子元素 <li>...</li> <li>...</li> ... </ul> </div> </template> <script> import BScroll from 'better-scroll' export default { mounted() { this.$nextTick(() => { this.scroll = new Bscroll(this.$refs.wrapper, {}) }) } } </script>
***重要:在mounted鉤子函數裏,this.$nextTick的回調函數中初始化better-scroll。是由於wrapper的DOM在這個時候已經渲染了,能夠正確計算其高度。
異步數據處理
<template> <div class="wrapper" ref="wrapper"> <ul class="content"> <li v-for="item in data">{{item}}</li> </ul> </div> </template> <script> import BScroll from 'better-scroll' export default { data() { return { data: [] } }, created() { requestData().then((res) => { //requestData()是僞代碼,實際用axios活vue-resource this.data = res.data this.$nextTick(() => { this.scroll = new Bscroll(this.$refs.wrapper, {}) }) }) } } </script>
初始化bs須要在數據獲取以後。之因此放在created而不是mounted,是由於requestData是一個異步過程,拿到相應數據時,DOM已經渲染好,可是,數據改變後到DOM從新渲染仍然是異步過程,因此仍是要異步初始化bs(nextTick)。
注意:在PC上,點擊事件會執行兩次。因爲better-scroll派發的事件有event_constructed:true屬性。能夠進行處理。
if (!event._constructed) { return; }
七、sass
Sass的學名叫「CSS預處理器」,就是在CSS的基礎上,引入了變量、嵌套、mixin(混合)、運算以及函數等功能,增長了代碼的靈活性,可讓咱們以更少的代碼實現一樣的效果,並且代碼的整潔度、可讀性更強。
.scss是Sass3引入的新語法,基本寫法與CSS大體相同
基本語法:
a)變量。css屬性的值(1px,bold)均可替換爲變量。
$box-color: red; //定義變量 ul{ color: $box-color; //引用 } li{ background-color: $box-color; //引用 }
b)嵌套
/***********************************************選擇器嵌套*******************************************/ div { h1 { color: #333; } p { margin-bottom: 1.4px; a { color: #999; } :hover{ color: #888; } } } /* 編譯後 */ div h1 { color: #333; } div p { margin-bottom: 1.4px; } div p a { color: #999; } div p:hover{ color: #888; } /***********************************************屬性嵌套*******************************************/ div { border: { style: solid; width: 1px; color: #ccc; } } //編譯後 div { border-style: solid; border-width: 1px; border-color: #ccc; }
c)繼承:使用選擇器的繼承,要使用關鍵詞@extend,後面緊跟須要繼承的選擇器。
.class1 { border: 1px solid #333; } .class2 { @extend .class1; background-color: #999; } //編譯後 .class1, .class2 { border: 1px solid #333; } .class2 { background-color: #999; }
d)Mixin混合器:使用@mixin聲明,經過@include minxin名稱調用
@mixin mixName { float: left; margin-left: 10px; } div { @include mixName; } //編譯後: div { float: left; margin-left: 10px; } /*帶參數的聲明及調用*/ @mixin left($value: 10px) { float: left; margin-left: $value; } div { @include left(66px); } //編譯後: div { float: left; margin-left: 66px; }
e)顏色函數
$box-color: red; li{ background-color: darken($box-color,30%); } //編譯後 li{ background-color: #660000; } //更多 lighten(#cc3,10%)//#d6d65c grayscale(#cc3)//#808080 complement(#cc3)//#33c
f)導入:@import "地址"; 如@import "../../common/scss/mixin.scss";
八、優化:
每次切換模塊後,都會從新渲染DOM,解決方法爲給APP.vue下的<vue-router 加入keep-alive></vue-router>,組建的切換狀態就會保留。
九、打包:
使用npm run build打包文件,其執行了node build/build.js腳本,最終產生一個dist目錄,裏面包含css,js,index.html文件,打包後文件經過HTTP server啓動(sell總目錄下建立一個produ.server.js寫完代碼後使用node prode.server.js啓動)
技巧:(1).若是要使用new建立對象,因爲本項目使用了ESlint檢查代碼規範,所以會報錯,在這裏使用/*eslint-disable no-new*/來跳過校驗;
(2). 在build->webpack.base.conf.js中,module.exports下的resolve的alias下能夠定義路徑,就不用每次引用時加./表示當前路徑 等相似問題了;
(3).圖標與文字不齊,可設置vertical-align:top來對齊,還不行能夠對圖片設置paddingtop。
(4).手機測試網頁技巧:將localhost換成本身的ip,而後複製地址欄地址,進入草料二維碼,而後生成二維碼,而後用手機掃一掃就能夠查看了,前提是,你手機和電腦必須在同一個局域網。