摘要:前言這是我第一個基于的項目作品,目的很簡單,學(xué)以致用,將之前的前端知識積累加上目前流行的前端框架,以項目的形式展現(xiàn)出來。即將屬性和請求返回數(shù)據(jù)對象合并到空對象,然后賦值給這里加上即提供了一種可擴(kuò)展的機(jī)制,倘若原來的屬性中有預(yù)定義的其他屬性。
前言
這是我第一個基于 Vue 的項目作品,目的很簡單,學(xué)以致用,將之前的前端知識積累加上目前流行的前端框架,以項目的形式展現(xiàn)出來。
源代碼:https://github.com/nanyang24/...
演示地址:https://ele.n-y.io/
Vue有自己的腳手架構(gòu)建工具vue-cli,使用起來非常方便,使用webpack來集成各種開發(fā)便捷工具,比如:
Hot-reload Vue的熱更新,修改代碼之后無需手動刷新網(wǎng)頁,對前端開發(fā)來說非常方便
PostCss,再也不用去管兼容性的問題了,只針對chrome這樣的現(xiàn)代瀏覽器寫css代碼,會自動編譯生成兼容多款瀏覽器的css代碼
ESlint,統(tǒng)一代碼風(fēng)格,規(guī)避低級錯誤,對于有代碼潔癖的人來說是不可或缺的
Bable,ES2015出來已經(jīng)有一段時間了,但是不少瀏覽器還沒有兼容ES6,有了bable,放心使用ES6語法,它會自動轉(zhuǎn)義成ES5語法
SCSS,一款 CSS預(yù)處理器,編譯后成正常的CSS文件。為CSS增加一些編程的特性
…
除此之外,vue-cli已經(jīng)使用node配置了一套本地服務(wù)器和安裝命令等,本地運(yùn)行和打包只需要一個命令就可以搞定,非常的方便
實現(xiàn)功能Goods、Ratings、Seller 組件視圖均可上下滾動
商品頁 點(diǎn)擊左側(cè)menu,右側(cè)list對應(yīng)跳轉(zhuǎn)到相應(yīng)位置
點(diǎn)擊list查看商品詳情頁,父子組件的通信
評論內(nèi)容可以篩選查看
購物車組件,包括添加刪除商品及動效,購物控件與購物車組件之間為兄弟組件通信,點(diǎn)擊購物車圖標(biāo),展示已選擇的商品列表
商家實景圖片可以左右滑動
loaclStorage 緩存商家信息(id、name)
組件關(guān)系├──app.vue │ ├──header.vue--頭部組件 │ │ ├──star.vue--星星評分組件 │ ├──goods.vue--商品組件 │ │ ├──shopcart.vue--購物車組件,包括小球飛入購物車動畫 │ │ ├──cartcontrol.vue--購買加減圖標(biāo)控件--選中數(shù)量返回給父組件goods,goods響應(yīng)后,重新計算選中數(shù)量,將數(shù)據(jù)發(fā)送給購物車組件, │ │ ├──food.vue--商品詳情頁 │ │ │ ├──ratingselect.vue--評價內(nèi)容篩選組件 │ ├──ratings.vue--評論組件 │ │ ├──ratingselect.vue--評價內(nèi)容篩選組件 │ ├──seller.vue--商家組件 獨(dú)立組件 ├──split.vue--關(guān)于分割線組件項目結(jié)構(gòu)
common/---- 文件夾存放的是通用的css和fonts components/---- 文件夾用來存放 Vue 組件 router/---- 文件夾存放的是vue-router相關(guān)配置(linkActiveClass,routes注冊組件路由) build/---- 文件是 webpack 的打包編譯配置文件 config/---- 文件夾存放的是一些配置項,比如我們服務(wù)器訪問的端口配置等 dist/---- 該文件夾一開始是不存在,在項目經(jīng)過 build 之后才會生成 prod.server.js---- 該文件是測試是模擬的服務(wù)器配置,用來運(yùn)行dist里面的文件,在config/index.js中,build對象中添加一條端口設(shè)置port:9000, App.vue---- 根組件,所有的子組件都將在這里被引用 index.html---- 整個項目的入口文件,將會引用我們的根組件 App.vue main.js---- 入口文件的 js 邏輯,在 webpack 打包之后將被注入到 index.html 中開發(fā)過程問題匯總: 1、better-scroll 插件在移動端使用時需要設(shè)置 click:true,否則移動端滑動無效 2、分開設(shè)置css樣式:
圖標(biāo)icon.css--文字圖標(biāo)樣式,通過icommon.io網(wǎng)站 將svg圖片轉(zhuǎn)成文字圖標(biāo)樣式
公共base.css--處理設(shè)備像素比的一些樣式,針對border-1px問題,不同設(shè)備像素比,顯示的線條粗細(xì)不同
工具mixin.css--設(shè)置border-1px樣式和背景樣式
移動端 border-1px 實現(xiàn)原理當(dāng)樣式像素一定時,因手機(jī)有320px,640px等.各自的縮放比差異,所以設(shè)備顯示像素就會有1Npx,2Npx。
公式:設(shè)備上像素 = 樣式像素 * 設(shè)備像素比
為了保證設(shè)計稿高度還原,采用 media + scale 的方法解決
屏幕寬度: 320px 480px 640px 設(shè)備像素比: 1 1.5 2 通過查詢它的設(shè)備像素比 devicePixelRatio 在設(shè)備像素比為1.5倍時, round(1px 1.5 / 0.7) = 1px 在設(shè)備像素比為2倍時, round(1px 2 / 0.5) = 1px
實現(xiàn)代碼
// SCSS 語法 @mixin border-1px($color) { position: relative; &::after { display: block; position: absolute; left: 0; bottom: 0; width: 100%; border-top: 1px solid $color; content: ""; } } @mixin border-none() { &::after{ display: none; } } @media (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5) { .border-1px { &::after { -webkit-transform: scaleY(0.7); transform: scaleY(0.7); } } } @media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) { .border-1px { &::after { -webkit-transform: scaleY(0.5); transform: scaleY(0.5); } } }3、sticky-footer布局
在 header 組件的詳情頁采用 sticky-footer 布局,主要特點(diǎn)是如果頁面內(nèi)容不夠長的時候,頁腳塊粘貼在視窗底部;如果內(nèi)容足夠長時,頁腳塊會被內(nèi)容向下推送
實現(xiàn):父級 position:fixed,內(nèi)容設(shè) 為padding-bottom:64px,頁腳相對定位,margin-top:-64px,clear:both
為了保證兼容性,父級要清除浮動
參考:
https://www.cnblogs.com/shico...
https://www.w3cplus.com/css3/...
// 左側(cè)固定width:80px,右側(cè)自適應(yīng) parent: display:fiexd; child-left: flex:0 0 80px child-right: flex:12、元素寬度自適應(yīng)設(shè)備寬度,且元素要求等寬高樣式
例如:商品詳情頁面的商品圖片展示樣式
// stylus語法 .img_header { position:relative width:100% // width是 設(shè)備寬度 height:0 padding-top:100% // 高度設(shè)為0,使用padding撐開 .img { position:absolute //定位布局 top:0 left:0 width:100% height:100% } }5、背景模糊效果
filter:blur(10px),注意,所有在內(nèi)的子元素也會模糊,包括文字,所以采用定位布局,背景多帶帶占用一個層,ios有一個設(shè)置backdrop-filter:blur(10px),只會模糊背景,但不支持android
6、transition過渡在購買控件中使用transition過渡效果,實現(xiàn)添加減少按鈕的動效,和小球飛入購物車的動效(模仿貝塞爾曲線的效果)
vue2.x里面定義了transition過渡狀態(tài),
name - string, 用于自動生成 CSS 過渡類名。
例如:name: "fade" 將自動拓展為.fade-enter,.fade-enter-active等。默認(rèn)類名為 "v" fade-enter fade-enter-active fade-leave fade-leave-active
包括transition過渡的鉤子函數(shù)
before-enter before-leave before-appear enter leave appear after-enter after-leave after-appear enter-cancelled leave-cancelled (v-show only) appear-cancelled7、seller組件: 問題一:seller頁面中商品商家實景圖片橫向滾動
解決方案:每個 li 要 display:inline-block,因為width不會自動撐開父級ul,所以需要將計算后的寬度賦值給ul的width,(每一張圖片的width+margin)*圖片數(shù)量-一個margin,因為最后一張圖片沒有margin
同時new BScroll里面要設(shè)置scrollX: true,eventPassthrough: "vertical", // 滾動方向橫向
問題分析:出現(xiàn)這種現(xiàn)象是因為better-scroll插件是嚴(yán)格基于DOM的,數(shù)據(jù)是采用異步傳輸?shù)模撁鎰偞蜷_,DOM并沒有被渲染,所以,要確保DOM渲染了,才能使用 better-scroll,
解決方案:用到mounted鉤子函數(shù),同時必須搭配this.$nextTick()
問題分析:出現(xiàn)這種情況是因為mounted函數(shù)在整個生命周期中只會只行一次
解決方案:使用watch方法監(jiān)控數(shù)據(jù)變化,并執(zhí)行滾動函數(shù) this._initScroll();this._initPicScroll();
使用window.localStorage保存和設(shè)置緩存信息,封裝在store.js文件內(nèi)
//將頁面信息保存到localStorage里 export function saveToLocal(id, key, value) { let store = window.localStorage._store_; // 新定義一個key值_store_,存放要保存的數(shù)據(jù)對象 // _store_ { // store[id]: { // key: value // } // } if (!store) { store = {}; store[id] = {}; } else { store = JSON.parse(store); // String格式--> json格式 if (!store[id]) { store[id] = {}; } } store[id][key] = value; window.localStorage._store_ = JSON.stringify(store); // 將json格式轉(zhuǎn)成String格式,存放到window.localStorage._store中 } //將localStorage信息設(shè)置到頁面中 export function loadFromLocal(id, key, defaults) { let store = window.localStorage._store_; if (!store) { // 一開始是沒有的,因為沒有點(diǎn)擊事件,所以顯示默認(rèn)數(shù)據(jù) return defaults; } store = JSON.parse(store)[id]; // 將json格式-->String格式 // console.log(store); // {"isFavorite":true} if (!store) { return defaults; } let ret = store[key]; return ret || defaults; }9、解析url,得到商家信息,包括id,name,在獲取數(shù)據(jù)時,直接賦值,商家的id或name會被丟掉
使用window.localStorage.search獲取url地址,并進(jìn)行解析
封裝在util.js文件內(nèi)
/** * 解析URL參數(shù) * @example ?id=12345&a=b * @return Object {id:12345, a:b} **/ export function urlParse() { let url = window.location.search; let obj = {}; let reg = /[?&][^?&]+=[^?&]+/g; let arr = url.match(reg); // ["?id=12345", "&a=b"] if (arr) { arr.forEach((item) => { let temArr = item.substring(1).split("="); let key = decodeURIComponent(temArr[0]); let value = decodeURIComponent(temArr[1]); obj[key] = value; }); } return obj; };
我們需要將得到的 id 和 name 帶到數(shù)據(jù)中,實際上在獲取數(shù)據(jù)的時候,并沒有帶著id和name,這時就要用到 es6 語法中Object.assign(),官方解釋為:可以把任意多個的源對象自身的可枚舉屬性拷貝給目標(biāo)對象,然后返回目標(biāo)對象。
this.seller = Object.assign({}, this.seller, response.data); //即將vm.seller屬性和請求返回數(shù)據(jù)對象合并到空對象,然后賦值給vm.seller,這里加上this.seller即提供了一種可擴(kuò)展的機(jī)制,倘若原來的屬性中有預(yù)定義的其他屬性。10、goods,ratings,seller組件之間切換時會重新渲染
解決方案:在 app.vu 內(nèi)使用 keep-alive,保留各組件狀態(tài),避免重新渲染
Vue 使用技巧 1、vue-router
使用
// app.vuehome about
// router: index.js import Vue from "vue"; import Router from "vue-router"; import goods from "components/goods/goods.vue"; import ratings from "components/ratings/ratings.vue"; import seller from "components/seller/seller.vue"; Vue.use(Router); const routes = [{ path: "/", redirect: "/goods" }, { path: "/goods", component: goods }, { path: "/ratings", component: ratings }, { path: "/seller", component: seller }]; export default new Router({ routes, linkActiveClass: "active" });2、axios
在vue1.x的時候,vue的官方推薦HTTP請求工具是vue-resource,但是在vue2.0的時候?qū)⑼扑]工具改成了axios。
如果想像以前使用 vue-resource 那樣 this.$http.get 調(diào)用,要這樣定義:
Vue.prototype.$http = axios;
通過 this.$http.get 來定義通過vue實例來發(fā)送get請求,然后通過then后面的回調(diào)函數(shù)將請求成功的數(shù)據(jù)接收,通過狀態(tài)碼來判斷是否成功以及復(fù)制給vue的數(shù)據(jù)對象。由于這里是用的mock數(shù)據(jù)(模擬后臺數(shù)據(jù)),所以用的模擬狀態(tài)碼。
const ERR_OK = 0;//表示沒有錯誤信息,即獲取數(shù)據(jù)成功 this.$http.get("/api/seller").then((response) => { response = response.data; if (response.errno === ERR_OK) { this.seller = Object.assign({}, this.seller, response.data); } });3、組件間通訊
vue是組件式開發(fā),所以組件間通訊是必不可少的
父傳子: props
子傳父: $emit
兄弟通訊: 1. event bus: 利用一個中間組件來作為信息傳遞中介;2. vuex: 信息樹
父傳子: propsvue提供了一種方式,即在子組件定義 props 來接受父組件傳遞來的數(shù)據(jù)對象。
// 父組件子傳父: $emit// 子組件 header.vue props: { seller: { type: Object } }
如果是子組件想傳遞數(shù)據(jù)給父組件,需要派發(fā)自定義事件,使用 $emit 派發(fā),
父組件使用v-on接收監(jiān)控(v-on可以簡寫成@)
// 子組件 RatingSelect.vue,派發(fā)自定義事件isContent,將this.onlyContent數(shù)據(jù)傳給父級 this.$emit("isContent", this.onlyContent); this.$emit("selRatings", this.selectType); // 父組件 foodInfo.vue 在子組件的模板標(biāo)簽里,使用v-on監(jiān)控isContent傳過來的數(shù)據(jù)非父子組件之間通信
大型項目可以用 Vue官方推薦的vuex
EventBus :https://n-y.io/vue-eventbus/
子組件A $emit 派發(fā)具體事件,由父組件 @ 監(jiān)聽得到數(shù)據(jù)
父組件再利用 $refs 直接訪問子組件B的方法,間接實現(xiàn)數(shù)據(jù)從子組件A傳遞至子組件B
4、組件提取管理將相同樣式或功能的區(qū)塊多帶帶提出來,作為一個組件。
另外組件中用到的圖片等資源就近維護(hù),即可以考慮在組件文件夾中新建images文件夾。
抽離組件遵循原則:
要盡量遵循單一職責(zé)原則,復(fù)用性更高,不要設(shè)置額外的margin等影響布局的東西
想要達(dá)到這種目的,有兩種方法,一種是利用重定向,另一種是利用vue-router的導(dǎo)航式編程。
1、重定向//在router的index.js文件中設(shè)置,要多寫一個對象,指向目標(biāo)組件 Vue.use(Router); const routes = [{ path: "/", redirect: "/goods" // 重定向 }, { path: "/goods", component: goods }, { path: "/ratings", component: ratings }, { path: "/seller", component: seller }]; export default new Router({ routes, linkActiveClass: "active" });2、導(dǎo)航式編程
router.push("/Goods");項目難點(diǎn) 1、關(guān)于購物車添加按鈕的動畫 html代碼
生成一個動畫小球的div,并且生成五個小球,五個是為了生成一定數(shù)量的小球來作為操作使用,按照小球動畫的速度,一般來說五個也可以保證有足夠的小球數(shù)量來運(yùn)行動畫
動畫的內(nèi)容分別是外層和內(nèi)層,外層控制動畫小球的軌道和方向,內(nèi)層控制動畫小球自身的運(yùn)行狀態(tài)
動畫使用vue的js鉤子實現(xiàn)
因為小球動畫只有一個方向(只執(zhí)行單方向從上到下滾落),所以只用了before-enter,enter,after-enter
用v-show控制小球的可見性,在動畫執(zhí)行期間可見,其余時候隱藏
js代碼//用了兩種方式的動畫,css和js鉤子//外層動畫 //內(nèi)層動畫
設(shè)置了balls數(shù)組來代表五個小球
設(shè)置了dropBalls數(shù)組正在運(yùn)行的小球
data(){ return { balls: [ {show: false}, {show: false}, {show: false}, {show: false}, {show: false} ], dropBalls: [] } },
只要觸發(fā)了drop事件,不止是drop事件里面的代碼會執(zhí)行,另外幾個vue的js監(jiān)聽鉤子也會一起按順序執(zhí)行
觸發(fā)了 drop 事件
beforeDrop 開始執(zhí)行
dropping 開始執(zhí)行
afterDrop 開始執(zhí)行
drop 事件的觸發(fā)可以通過點(diǎn)擊 cartcontrol 組件的添加小球按鈕 addCart 事件觸發(fā)使用 $emit ,也可以父組件 this.$refs.shopcart.drop(target); 直接觸發(fā)
這么做的目的是實現(xiàn),在子組件 cartcontrol 點(diǎn)擊之后,可以將具體點(diǎn)擊的 dom 傳給父組件 goods 然后再傳給子組件 shopcart,(因為目前他們之間的通道就是這樣,shopcart子組件并沒有導(dǎo)入cartcontrol子組件,所以沒有直接通訊)這樣就實現(xiàn)了多個組件之間的通訊(也可以使用 EventBus 和 vuex),從而可以實現(xiàn)需求,例如這里就是實現(xiàn)點(diǎn)擊子組件 cartcontrol 后添加一個動畫,將小球滑落到另外一個組件shopcart
$emit 是觸發(fā)當(dāng)前實例上的事件。附加參數(shù)都會傳給監(jiān)聽器回調(diào)。
methods: { drop(el) { //觸發(fā)一次事件就會將所有小球進(jìn)行遍歷 for (let i = 0; i < this.balls.length; i++) { let ball = this.balls[i]; if (!ball.show) { //將false的小球放到dropBalls ball.show = true; ball.el = el; //設(shè)置小球的el屬性為一個dom對象 this.dropBalls.push(ball); return; } } }, beforeDrop(el){ //這個方法的執(zhí)行是因為這是一個vue的監(jiān)聽事件 let count = this.balls.length; while (count--) { let ball = this.balls[count]; if (ball.show) { let rect = ball.el.getBoundingClientRect(); //獲取小球的相對于視口的位移(小球高度) let x = rect.left - 32; let y = -(window.innerHeight - rect.top - 22); //負(fù)數(shù),因為是從左上角往下的的方向 el.style.display = ""; //清空display el.style.webkitTransform = `translate3d(0,${y}px,0)`; el.style.transform = `translate3d(0,${y}px,0)`; //處理內(nèi)層動畫 let inner = el.getElementsByClassName("inner-hook")[0]; //使用inner-hook類來單純被js操作 inner.style.webkitTransform = `translate3d(${x}px,0,0)`; inner.style.transform = `translate3d(${x}px,0,0)`; } } }, dropping(el, done) { //這個方法的執(zhí)行是因為這是一個vue的監(jiān)聽事件 /* eslint-disable no-unused-vars */ let rf = el.offsetHeight; //觸發(fā)重繪html this.$nextTick(() => { //讓動畫效果異步執(zhí)行,提高性能 el.style.webkitTransform = "translate3d(0,0,0)"; el.style.transform = "translate3d(0,0,0)"; //處理內(nèi)層動畫 let inner = el.getElementsByClassName("inner-hook")[0]; //使用inner-hook類來單純被js操作 inner.style.webkitTransform = "translate3d(0,0,0)"; inner.style.transform = "translate3d(0,0,0)"; el.addEventListener("transitionend", done); //Vue為了知道過渡的完成,必須設(shè)置相應(yīng)的事件監(jiān)聽器。 }); }, afterDrop(el) { //這個方法的執(zhí)行是因為這是一個vue的監(jiān)聽事件 let ball = this.dropBalls.shift(); //完成一次動畫就刪除一個dropBalls的小球 if (ball) { ball.show = false; el.style.display = "none"; //隱藏小球 } } }
關(guān)于 transitionend
關(guān)于drop方法,是實現(xiàn)每一個ball的show屬性和el屬性處理,并且點(diǎn)擊一次會自動將一個小球放到 dropBalls 數(shù)組里面,放到里面就代表的是一個小球已經(jīng)被開始執(zhí)行動畫,但是由于動畫是異步的,所以先主動設(shè)置.
關(guān)于 getBoundingClientRect (位移的計算是從左上角開始)
使用 getBoundingClientRect 獲取到當(dāng)前元素的坐標(biāo),然后需要位移的left減去元素的寬獲取真正的最終位移x坐標(biāo)
使用 getBoundingClientRect 獲取到當(dāng)前元素的坐標(biāo),然后需要當(dāng)前屏幕的高度減去元素的 top 再減去元素本身的高度獲取到真正的最終位移 y 坐標(biāo),并且這個是負(fù)數(shù),因為是從左上角往下的方向
關(guān)于html重繪
因為瀏覽器對于重繪是有要求并且是有隊列完成的,這是主要為了性能,雖然動畫隱藏了小球display none,但沒有觸發(fā)html重繪,或者說沒有立即觸發(fā)html重繪,所以需要手動
let rf = el.offsetHeight; 這是一個手動觸發(fā)html重繪的方法
網(wǎng)頁性能管理詳解
高性能JavaScript 重排與重繪
css代碼.ball-container .ball position: fixed //小球動畫必須脫離html布局流 left: 32px bottom: 22px z-index: 200 transition: all 0.4s cubic-bezier(0.49, -0.29, 0.75, 0.41) .inner width: 16px height: 16px border-radius: 50% background: rgb(0, 160, 220) transition: all 0.4s linear
關(guān)于cubic-bezier(0.49, -0.29, 0.75, 0.41),是動畫拋物曲線(貝塞爾曲線)的配置,基于css3實現(xiàn),參考貝塞爾曲線與CSS3動畫、SVG和canvas的基情 ,至于拋物線放在外層就是為了控制內(nèi)層的元素的軌道和方向的.
2、星星組件star.vue整個流程是:
綁定星星類型的class(48,36,24尺寸),使用starType
使用class來顯示星星,有3種類型,全星,半星,無星,使用star-item代表星星本身,然后分別使用on,off,half代表三種不同類型的星星
一個span代表一個星星項目,并且使用v-for循環(huán)將星星項目輸出
最后形成的星星html就類似這樣
html部分
js部分
設(shè)置常量是為了方便解耦
星星計算比較巧妙(根據(jù)分?jǐn)?shù)轉(zhuǎn)換為星星數(shù))
對于分?jǐn)?shù)score進(jìn)行乘以2然后向下取整,然后再除以2,是為了獲取所有星星的數(shù)量,并且這個數(shù)量是0.5倍數(shù)的,例如4.6 2就是9.2,然后向下取整是9,然后再除以2就是4.5,那么就可以得到一個0.5倍數(shù)的星星數(shù),可以轉(zhuǎn)換為4個全星+一個半星
對于非整數(shù)的星星算作是半個星星,需要知道是否有存在這種情況,所以分?jǐn)?shù)score%1 ,例如 8 % 1是0,8.5 % 1就不是0,并且這個半星只會出現(xiàn)一次,因為半星狀態(tài)就只要一個
沒有星星的部分是要補(bǔ)全的,這里使用while循環(huán)來處理這種情況
css部分引入mixin.styl是為了使用bg-image的mixin,因為之前做了一個mixin是專門處理2x和3x圖片的轉(zhuǎn)換
因為這里有3種類型的星星圖片,分別是48尺寸,36尺寸,24尺寸,所以對于每一個類別的圖片分別使用一種class做對應(yīng)
每一種星星的尺寸都是有一種相對應(yīng)的圖片的,例如48尺寸的星星就會有,并且圖片放在相對應(yīng)的vue文件目錄下
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]3、ratingselect組件 html代碼
備注:父組件food.vue傳入的數(shù)據(jù)
方法有:@select="selectRating" @toggle="toggleContent",通過將字組件的方法和父組件的方法進(jìn)行關(guān)聯(lián),這樣就能夠?qū)崿F(xiàn)跨組件通訊和操作
屬性有::selectType="selectType":onlyContent="onlyContent" :desc="desc":ratings="food.ratings",這是通過pros傳入到子組件的屬性,將父組件的數(shù)據(jù)傳到子組件里面,也帶有一種通過父組件來初始化子組件屬性的意思.
@click="select(2,$event)" select方法傳入類型和事件,然后在methods里面調(diào)用父組件的方法,實現(xiàn)子組件控制父組件的目的
:class="{"active":selectType ===2}" 根據(jù)類型來確定顯示的class,實現(xiàn)不同類型顯示不同樣式的目的
positives.length 使用計算屬性自動計算類型數(shù)組的長度,用來顯示不同類型的數(shù)量
@click="toggleContent" :class="{"on":onlyContent}"
toggleContent 控制是否展示有內(nèi)容的rate,也是在methods里面調(diào)用父組件的方法,實現(xiàn)子組件控制父組件的目的
綁定on這個class來控制該按鈕的樣式
JS代碼const POSITIVE = 0; //設(shè)置顯示常量 const NEGATIVE = 1; const ALL = 2; export default{ props: { ratings: { //傳入ratings數(shù)組,跟food.ratings關(guān)聯(lián) type: Array, default(){ return []; } }, selectType: { //跟selectType關(guān)聯(lián),通過在父組件里面設(shè)置這3個值來實現(xiàn)控制子組件的操作 type: Number, default: ALL }, onlyContent: { //跟onlyContent關(guān)聯(lián) type: Boolean, default: true }, desc: { //跟desc關(guān)聯(lián) type: Object, default(){ return { all: "全部", positive: "滿意", negative: "不滿意" } } } }, computed: { positives(){ //自動過濾rateType(正面的rate) return this.ratings.filter((rating) => { //js的filter函數(shù)會返回一個處理后的(為true)結(jié)果的結(jié)果數(shù)組 return rating.rateType === POSITIVE; }) }, negatives(){ //自動過濾rateType(反面的rate) return this.ratings.filter((rating) => { return rating.rateType === NEGATIVE; }) } }, methods: { select(type, event) { // 選擇rateType并且通知父組件 if (!event._constructed) { return; } this.$emit("select", type); // 派發(fā)事件,父組件監(jiān)聽此事件 }, toggleContent(event) { // 選擇是否顯示有內(nèi)容的rate,并且通知父組件 if (!event._constructed) { return; } this.$emit("toggle"); } } }4、商品區(qū)域goods.vue HTML
v-for使用已經(jīng)很常見了,不過這里需要了解,vue1和2有區(qū)別,現(xiàn)在是用vue2,所以index變量傳遞會變成現(xiàn)在這種模式 (item,index) in goods
vue傳遞原生事件使用$event
:class="{"current":currentIndex === index}" 是vue的綁定class的使用方法,通過綁定一個class變量來直接操作,并且這里的邏輯會跟js代碼里面對應(yīng)
通過currentIndex和index做對比,來確認(rèn)是否添加current類,他們之間的對比關(guān)系也就是 menu 區(qū)域和 foods 區(qū)域的顯示區(qū)域的對比關(guān)系
通過添加current類來實現(xiàn)當(dāng)前頁面的區(qū)域的樣式變化
currentIndex是一個計算屬性,可以隨時變化并且直接反應(yīng)到dom上(看js里面邏輯)
v-show 和 v-if 的區(qū)別官網(wǎng)已經(jīng)說過
v-if 是“真正的”條件渲染,因為它會確保在切換過程中條件塊內(nèi)的事件監(jiān)聽器和子組件適當(dāng)?shù)乇讳N毀和重建。
v-if 也是惰性的:如果在初始渲染時條件為假,則什么也不做——直到條件第一次變?yōu)檎鏁r,才會開始渲染條件塊。
一般來說, v-if 有更高的切換開銷,而 v-show 有更高的初始渲染開銷。因此,如果需要非常頻繁地切換,則使用 v-show 較好;如果在運(yùn)行時條件不太可能改變,則使用 v-if 較好。
$refs 的使用是vue操作dom的一種方式:
ref 被用來給元素或子組件注冊引用信息。引用信息將會注冊在父組件的 $refs 對象上。
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素; 如果用在子組件上,引用就指向組件實例:
hook鉤子類的使用,需要結(jié)合js里面的語法來看,這個類只是用來操作,不會產(chǎn)生dom的渲染,方便js控制清晰.
JS
這里最關(guān)鍵的是menu和food兩個區(qū)域的對應(yīng)處理:
在vue實例生命周期的開始created分別加載_initScroll和_calculateHeight
通過 _calculateHeight 計算foods內(nèi)部每一個塊的高度,組成一個數(shù)組listHeight
在 _initScroll 里面,設(shè)置了bscroll插件的一個監(jiān)聽事件scroll,將food區(qū)域當(dāng)前的滾動到的位置的y坐標(biāo)設(shè)置到一個vue實例屬性 scrollY this.scrollY = Math.abs(Math.round(pos.y));
通過計算屬性currentIndex,獲取到food滾動區(qū)域?qū)?yīng)的menu區(qū)域的子塊的索引,然后通過設(shè)置一個class來做樣式切換變化:class="{"current":currentIndex === index},實現(xiàn)聯(lián)動
另外當(dāng)點(diǎn)擊menu 區(qū)域的時候,會觸發(fā)selectMenu事件,也會根據(jù)點(diǎn)擊到的menu子塊的索引然后去觸發(fā)food區(qū)域滾動到對應(yīng)的高度區(qū)塊區(qū)間this.foodsScroll.scrollToElement(el, 300);
這樣完成整個對應(yīng).
拋物線小球動畫橫跨多個vue組件(也可以說是橫跨了多個DOM)
better-scroll需要安裝,npm安裝,具體參看better-scroll官網(wǎng)
關(guān)于在selectMenu中點(diǎn)擊,在pc界面會出現(xiàn)兩次事件,在移動端就只出現(xiàn)一次事件的問題:
原因:
bsScrooler會監(jiān)聽事件(例如touchmove,click之類),并且阻止默認(rèn)事件(prevent stop),并且他只會監(jiān)聽移動端的,pc端的沒有監(jiān)聽
在pc頁面上 bsScroller也派發(fā)了一次click事件,原生也派發(fā)了一次click事件
解決:
針對bsScroole的事件,有_constructed: true,所以做處理,return 掉非bsScroll的事件
SCSS 預(yù)處理器 css預(yù)處理器index.scss是SCSS文件的入口文件,里面使用 @import 引入各種SCSS文件
@import "./base"; @import "./mixin"; @import "./icon.css";
在入口文件main.js中全局引用index.scss
import "common/css/index.scss";關(guān)于ESlint
eslint 是一個js代碼風(fēng)格檢查器,配合vue-cli腳手架中的熱更新,可以很方便的定位和提示錯誤。在公司多人協(xié)作開發(fā)時可以確保代碼風(fēng)格保持一致,可以很方便的閱讀他人的代碼。
手機(jī)測試網(wǎng)頁技巧將 localhost 換成自己的ip (Windows在命令行執(zhí)行ipconfig查看,mac執(zhí)行ifconfig查看)
然后復(fù)制地址欄地址,進(jìn)入草料二維碼,然后生成二維碼,然后用手機(jī)掃一掃就可以查看了,前提是,你手機(jī)和電腦必須在同一個局域網(wǎng)。
項目運(yùn)行克隆項目到本地 git clone [email protected]:nanyang24/eleme-vue.git 安裝依賴 npm install 本地開發(fā),開啟服務(wù)器,瀏覽器訪問http://localhost:8080 npm run dev 構(gòu)建生產(chǎn) npm run build 運(yùn)行打包文件 node prod.server.js 會看到 Listening at http://localhost:9000 在瀏覽器中打開即可學(xué)習(xí)參考
Vue2.0 官網(wǎng): https://vuefe.cn/v2/guide/
vue-cli:https://github.com/vuejs/vue-cli
vue-router 2.0文檔:https://router.vuejs.org/zh-cn/
axios:https://github.com/axios/axios
webpack官網(wǎng):https://webpack.js.org/
better-scroll 插件使用:https://github.com/ustbhuangy...
SCSS 預(yù)處理器: https://www.sass.hk/
ESlint 代碼風(fēng)格檢查:http://eslint.org/docs/rules/
ES6 入門: http://es6.ruanyifeng.com/
Sticky footers http://www.w3cplus.com/css3/c...
Flex 彈性布局: http://www.ruanyifeng.com/blo...
設(shè)備像素比:http://www.zhangxinxu.com/wor...
貝塞爾曲線生成器:http://cubic-bezier.com/#.17,...
localStorage 本地存儲: http://www.cnblogs.com/st-les...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107581.html
摘要:項目地址郵箱求工作杭州項目介紹來公司實習(xí),由于技術(shù)棧原因,學(xué)習(xí)一下,以此項目來做練習(xí)。項目暫時只能在開發(fā)環(huán)境運(yùn)行。 項目地址 https://github.com/Gitjinfeiy... 郵箱 [email protected](求工作 杭州) 項目介紹 來公司實習(xí),由于技術(shù)棧原因,學(xué)習(xí)一下angular2,以此項目來做練習(xí)。 項目暫時只能在開發(fā)環(huán)境運(yùn)行。...
摘要:前言本文的前身是源自上的項目但由于該項目上次更新時間為年月日,很多內(nèi)容早已過期或是很多近期優(yōu)秀組件未被收錄,所以小肆今天重新更新了內(nèi)容并新建項目。提交的項目格式如下項目名稱子標(biāo)題相關(guān)介紹如果收錄的項目有錯誤,可以通過反饋給小肆。 前言 本文的前身是源自github上的項目awesome-github-vue,但由于該項目上次更新時間為2017年6月12日,很多內(nèi)容早已過期或是很多近期優(yōu)...
摘要:一個基于全家桶開發(fā)的仿知乎日報單頁應(yīng)用項目地址源碼地址項目在線地址在線地址模式下推薦使用移動端模式瀏覽去觀看如果覺得做得還不錯或者項目源碼對您有幫助希望您小抬右手到右上角點(diǎn)一個您的支持是作者長期更新維護(hù)的動力項目起源從二月份開始學(xué)習(xí)學(xué)習(xí)了 Vue-News 一個基于vue全家桶開發(fā)的仿知乎日報單頁應(yīng)用 項目github地址:源碼地址 項目在線地址:在線地址 (PC模式下推薦使用chro...
摘要:毫無疑問,設(shè)計模式于己于他人于系統(tǒng)都是多贏的設(shè)計模式使代碼編寫真正工程化設(shè)計模小書前端掘金這是一本關(guān)于的小書。 JavaScript 常見設(shè)計模式解析 - 掘金設(shè)計模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總結(jié)。使用設(shè)計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。毫無疑問,設(shè)計模式于己于他人于系統(tǒng)都是多贏的;設(shè)計...
閱讀 1363·2021-09-28 09:43
閱讀 4163·2021-09-04 16:41
閱讀 1928·2019-08-30 15:44
閱讀 3750·2019-08-30 15:43
閱讀 787·2019-08-30 14:21
閱讀 2044·2019-08-30 11:00
閱讀 3330·2019-08-29 16:20
閱讀 1932·2019-08-29 14:21