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