1. 程式人生 > >商品詳情頁(food組件)

商品詳情頁(food組件)

text itl 哪些 編程思想 如果 遮蓋 foo lan ima

前言

本節分為四大塊:

1. 商品詳情頁 food 組件(布局樣式、第三方插件庫better-scroll 的應用)

2. split 組件

3. ratingselect 組件

4. 評價列表

技術分享圖片

商品詳情頁 food 組件

1. CSS 設置

技術分享圖片
  1 <style lang="stylus" rel="stylesheet/stylus">
  2   @import "../../common/stylus/mixin.styl"
  3 
  4   .food
  5     position fixed
  6     left 0
  7     top 0
  8     bottom 48px
9 z-index 30 10 width 100% 11 background #fff 12 transform translate3d(0, 0, 0) 13 &.move-enter-active, &.move-leave-active 14 transition all 0.2s linear 15 &.move-enter, &.move-leave-active 16 transform translate3d(100%, 0, 0) 17 .image-header 18
position relative 19 width 100% 20 height 0 21 padding-top 100% 22 img 23 position absolute 24 left 0 25 top 0 26 width 100% 27 height 100% 28 .back 29 position absolute 30 left 0 31 top 10px 32 .icon-arrow_lift
33 display block 34 /*點擊區域變大*/ 35 padding 10px 36 font-size 20px 37 color #fff 38 .content 39 position relative 40 padding 18px 41 .title 42 margin-bottom 8px 43 line-height 14px 44 font-size 14px 45 font-weight 700 46 color rgb(7, 17, 27) 47 .detail 48 margin-bottom 18px 49 height 10px 50 line-height 10px 51 font-size 0 52 .sell-count, .rating 53 font-size 10px 54 color rgb(147, 153, 159) 55 .sell-count 56 margin-right 12px 57 .price 58 font-weight 700 59 line-height 24px 60 .now 61 margin-right 8px 62 font-size 14px 63 color rgb(240, 20, 20) 64 .old 65 text-decoration line-through 66 font-size 10px 67 color rgb(147, 153, 159) 68 .cartcontrol-wrapper 69 position absolute 70 right 12px 71 bottom 12px 72 .buy 73 position absolute 74 right 18px 75 bottom 18px 76 /*因為要蓋住cartcontrol組件*/ 77 z-index 10 78 height 24px 79 line-height 24px 80 padding 0 12px 81 box-sizing border-box 82 border-radius 12px 83 font-size 10px 84 color #fff 85 background-color rgb(0, 160, 220) 86 opacity 1 87 &.fade-enter-active, &.fade-leave-active 88 transition all 0.2s linear 89 &.fade-enter, &.fade-leave-active 90 opacity 0 91 z-index -1 92 .info 93 padding: 18px 94 .title 95 line-height: 14px 96 margin-bottom: 6px 97 font-size: 14px 98 color: rgb(7, 17, 27) 99 .text 100 line-height: 24px 101 padding: 0 8px 102 font-size: 12px 103 color: rgb(77, 85, 93) 104 .rating 105 padding-top: 18px 106 .title 107 line-height: 14px 108 margin-left: 18px 109 font-size: 14px 110 color: rgb(7, 17, 27) 111 .rating-wrapper 112 padding 0 18px 113 .rating-item 114 position relative 115 padding 16px 0 116 border-1px(rgba(7, 17, 27, 0.1)) 117 .user 118 position absolute 119 top 16px 120 right 0 121 line-height 12px 122 font-size 0 123 .username 124 margin-right 6px 125 display inline-block 126 vertical-align top 127 font-size 10px 128 color rgb(147, 153, 159) 129 .avatar 130 border-radius 50% 131 .time 132 margin-bottom 6px 133 line-height 12px 134 font-size 10px 135 color rgb(147, 153, 159) 136 .text 137 line-height 16px 138 font-size 12px 139 color rgb(7, 17, 27) 140 .icon-thumb_up, .icon-thumb_down 141 margin-right 4px 142 line-height 16px 143 font-size 12px 144 .icon-thumb_up 145 color rgb(0, 160, 220) 146 .icon-thumb_down 147 color rgb(147, 153, 159) 148 .no-rating 149 padding 16px 0 150 font-size 12px 151 color rgb(147, 153, 159) 152 </style>
CSS 設置

1)相對於屏幕進行定位,使用 fixed 布局。

2)底部有購物車,所以設置 bottom 為 48px。

3)z-index 的值應該小於購物車詳情層的 z-index,因為購物車詳情層彈出應該要遮蓋住商品詳情層。

4)加上 transition 動畫

5)圖片高度應該和屏幕寬度一樣,是動態變化的。圖片加載是異步過程,如果不設置圖片高度,等到圖片加載完畢,頁面高度會突然被撐開。如何解決?先把寬高設好,設置 height 0,padding-top 100%。這是 W3C 的一個特定寫法,當 padding 的 top 或 bottom 設置為100% 時,會相對於盒子的 width 100%,這就相當於有一個寬高相等的盒子。(同理,當 padding 的 left 或 right 設置為100% 時,會相對於盒子的 height 100%)

2. 數據獲取

技術分享圖片
 1 food.vue文件
 2     props: {
 3       food: {
 4         type: Object
 5       }
 6     },
 7 
 8 
 9 goods.vue文件
10     <food :food="selectedFood" ref="food"></food>
11 
12     import food from ‘../../components/food/food‘;
13     data() {
14       return {
15         selectedFood: {}
16       };
17     },
18     methods: {
19       selectFood(food, event) {
20         if (!event._constructed) {
21           // eslint-disable-next-line
22           return;
23         }
24         this.selectedFood = food;
25       },
26     }
數據獲取

1)商品詳情頁關聯的是商品本身,也就是食品分類下的每個商品。使用 props 接收 food 對象。

2)在 goods 組件中引用 food 組件,並且傳入food,設定變量為 selectedFood(即選中的 food),在 data 中定義該變量,為一個空對象。

3)selectedFood 是選中的 food,那麽什麽時候選中?當點擊 food 時。如何實現:在 li 中添加點擊事件 selectFood(food,$event),傳入參數 food,因為這裏是 foodWrapper,所以點擊的時候也要拿到 event,接著在在 methods 中實現該方法。先 return 掉瀏覽器默認的點擊事件,將參數 food 傳遞給變量 selectedFood。如何檢驗:在瀏覽器調試窗口中找到 food 層,取消display屬性,看看布局有沒有錯。

3. show 方法的實現:點擊商品時,商品詳情層展開

技術分享圖片
 1 food.vue文件
 2     data() {
 3       return {
 4         showFlag: false
 5         }
 6       };
 7     },
 8     methods: {
 9       show() {
10         this.showFlag = true;
11       },
12     }
13 
14 goods.vue文件
15     methods: {
16       selectFood(food, event) {
17         this.$refs.food.show();
18       }
19     }
show 方法

在 food 組件中定義 show 方法,show 方法通過改變 showFlag 的值來實現商品詳情層的展開功能,在此之前,需要在 data 中先定義 showFlag。然後在 goods 組件中通過 ref 獲取組件,並通過 $refs 調用子組件的 show 方法。

PS:1)父組件可以調用子組件方法,子組件不能調用父組件方法。2)設計規範:下劃線開頭是私有方法(_drop)。

4. 給返回按鈕添加點擊事件 hide

1)CSS設置:(display block,padding 10px)先設置display,才能設置padding,使點擊區域變大。

2)hide 方法通過改變 showFlag 的值為 false 來實現返回功能。
設置其他樣式

5. better-scroll 的使用

原理:當內部(content)的內容高度大於視口高度,則產生滾動效果

固定框架:外層是一個 wrapper,裏面有一個 content,並且這個 content 高度是由其中的內容撐開的。

使用:better-scroll 應該綁定在最外層(.food)。依舊是通過 ref 獲取組件,並通過 $refs 調用組件。better-scroll 應該在商品詳情層展開時就進行初始化,所以其初始化應該在 show 方法中。

6. 添加購物車按鈕

有兩種樣式:當加入商品時,“加入購物車” 文字消失,顯示 cartcontrol 組件。所以應該加入兩個層,這兩個層平級,分別是 buy 層和 cartcontrol 層。

1)這兩個層都是絕對定位。

2)buy 層加入 transition 動畫及 v-show 指令(當 food.count 不存在或等於 0 時,該層顯示)。

3)buy 層進行樣式設計:z-index 10,因為要蓋住 cartcontrol 組件。

4)點擊按鈕事件
addFirst,不傳參數的話,則默認參數為event
不傳參數得寫為addFirst,而不能寫成addFirst()


引入vue,第一次利用Vue.set,將this.count置為1。

增加點擊效果,要將事件傳出去


看不到小球位置,是因為display瞬間變成none,結果找不到位置,
讓購物車的消失做成一個動畫,這樣就不會立刻隱藏,不會立刻display被設置none,位置就能被計算。

加入購物車,漸隱效果,漸隱過程中,元素位置沒變,就可以正確拿到高度

點擊小球會觸發商品詳情頁,這是因為事件冒泡,所以要阻止事件冒泡
給cartcontrol組件的加號減號小球添加@click.stop.prevent="decreaseCart"事件

分隔布局,組件,引入
food.info不是每個數據都有,所以food.info加v-show

接下來寫評價模塊


一個變量控制評價數組,一個變量維護描述,一個變量是否只看內容,一個看類型
先寫props

通過父組件傳入數據,先通過data綁定一些東西
在show中初始化這些數據。因為這個組件被多個商品使用,當傳入商品時,希望這些屬性的狀態都是初始化的狀態
ratings是food.ratings

接下來寫樣式
為什麽不設置全padding,而設置padding-top為0,是因為下邊有一條邊框是貫穿整個界面的。


寫組件ratingselect的樣式
為什麽不寫padding而寫margin,是因為下面有一條線,寫padding會影響到線


什麽時候區塊會被active?:class

驗證:food組件,this.selectType = 1或0;

寫switch樣式

on樣式的使用,驗證(food。vue)this.onlyContent = false;

給組件增加事件:給按鈕增加click事件,給switch增加事件

clcik事件為什麽有event,因為點擊區塊,區塊外層有better-scroll,實現點擊功能。這裏同樣是以$emit將數據傳出去

Q:props雙向綁定變成單向
http://www.jb51.net/article/98881.htm


vue報錯Module build failed: ParseError: unexpected "indent"解決辦法
因為css代碼中註釋應該是/* 消除空白字符影響 */,而寫成// 消除空白字符影響(這是自動補全功能自己添加的註釋符號,很奇怪)

改變selectType怎麽通知父組件怎麽改變selectType的值呢,依舊需要通過派發事件給父組件,然後讓父組件監聽這個事件


再添加點擊事件toggleContent

接下來給數字動態化

接下來點擊按鈕與列表綁定,實時改變

接下來寫評價列表樣式:
有列表,顯示列表,沒有列表,顯示沒有列表
數據是時間戳,必須轉換成文本


贊還是貶,因為:class是一個對象,對象是可以繼續添加的
樣式設置:右側是絕對定位,定位到右上角

PS:不刷新也可以正常顯示,因為reload方法會重新加載。需要刷新的原因:如果過程中高度撐高,better-scroll高度計算可能不正確,因為不會重新refresh


根據列表的點擊,過濾一些評論,哪些顯示哪些不顯示

v-show綁定對象、屬性、字段、函數,
首先是按鈕的點擊(rating.rateType)以及是否只顯示有內容的評論(rating.text)

綁定了一個表達式,這個表達式是函數計算的結果


給selectRating和toggleContent方法加上refresh方法,即選擇後重新計算高度,防止列表回彈
改變數據時,DOM更新是異步的,所以要寫在nextTick接口中

評價為空,顯示暫無評價

PS:3、用毫秒時間戳初始化日期對象
var timestamp=new Date().getTime(); console.log( new Date(timestamp) ); //Tue Jun 06 2017 11:06:59 GMT+0800 (中國標準時間)
var date3 = new Date( timestamp - 1 * 60 * 60 * 1000); console.log(date3); // Tue Jun 06 2017 10:06:59 GMT+0800 (中國標準時間)
說明:時間戳是指格林威治時間1970年01月01日00時00分00秒(北京時間1970年01月01日08時00分00秒)起至現在的總秒數。時間戳唯一地標識某一刻的時間。

時間戳的換算,換成時間字符串
要轉換成字符串,可以用vue寫一個filters
可以在組件中定義組件級別的filters,filters中有一個formatDate(),formatDate中接受一個參數,即時間戳。要實現函數formatDate,需要在js模塊中實現,在js中創建date.js。
首先拿到時間戳,先轉換成Date類型的對象。然後將Date類型轉換成所需要的年月日時間的形式。可以寫一個函數,該函數:formatDate,去完成格式化字符串。希望可以在通用的地方中寫,所以寫在js文件中。這就是js模塊化編程思想。將一個通用的方法抽象成模塊。

在js文件中export這個方法,該方法接收兩個參數,第一個參數是date,第二個參數是字符串。
然後在food。vue中調用該模塊。
import {formatDate} from ‘common/js/date‘;
{formatDate}與cartcontrol的區別:
cartcontrol組件時通過export default。而模塊是通過export function,也就是說這個模塊其實可以同時export多個function,在引入時可以這麽寫{formatDate,a},可以import多個模塊,因為這個模塊不是default的。

實現{formatDate}方法:
date輸入是時間類型,輸出是字符串。輸入除了string類型還有一個格式化的字符串(就是兩個參數),輸出就是把字符串轉成需要的模式。
可以利用正則表達式來寫。傳入的參數是yyyy-MM-dd hh:mm,可以利用正則表達式遍歷這個字符串,將符合規則的表達式替換需要的年月日形式。
除了年是4個,其余都是2個。這裏就是將yyyy替換成為真實的數據。
先替換年:定義規則:匹配到以y開頭一個或多個的字符串。在字符串中查找匹配前面定義的規則(.test(fmt))。
舉個例子:這裏傳入的fmt="yyyy-MM-dd hh:mm",在正則表達式中:+ 代表匹配前面的子表達式一次或多次。/(y+)/代表的規則是找到以y開頭的字符串。所以這裏找到的是yyyy。
匹配到相應的字符串後,找到相應數據(比如:2016),然後替換掉符合規則的字符串,即最終替換結果為(2016-MM-dd hh:mm)。
如何實現:字符串有一個replace方法,第一個參數是被替換的字符串,第二個參數是替換的字符串。
RegExp.$1 代表的是找到的符合規則的字符串(即yyyy),getFullYear() 方法可返回一個表示年份的 4 位數字(假設這裏是2016)。要通過substr將其轉換成 4 位的字符串。
substr(start,length) 方法可在字符串中抽取從 start 下標開始的指定數目的字符。length參數省略的話,則返回從開始位置到結尾的字串。
substr(4 - RegExp.$1.length):
RegExp.$1.length的值是4,則4 - RegExp.$1.length為0,表示從getFullYear()返回的數字中抽取第一個位置到最後一個位置的字串。也就是說,從返回的數字2016中抽取第一個位置到最後一個位置的字串,結果就是2016,不過類型由數字變成字符串,剛好符合replace方法對參數類型的限制。

再舉個例子:假設fmt="yy-MM-dd hh:mm",其余不變,則最後從2016抽取第三個位置到最後一個位置的字串,就是16

除了年份比較特殊,其余的都一樣,可以先定義一個對象o,這個對象是一個正則表達式,對應所替換的內容。
其中月份比較特殊,getMonth()方法返回的值是0到11,為了取到正確的值,要加1。


定義完表達式對象,接下來遍歷該對象。
要先通過RegExp方法去構造一個正則表達式,依舊使用反引號和花括號結合的方式傳入變量k,變量k的值是M+、d+這一類,構造完正則表達式,遍歷字符串fmt,看看有沒有符合規則的,有的話,替換真實數據。

PS:一個是定義死了正則表達式(/(y+)/),一個動態構造正則表達式(RegExp(`(${k})`))

先定義要替換的值,末尾的這一步:+ ‘‘,是為了將數字轉換成字符串。

替換這裏需要註意,不能直接替換掉符合正則表達式規則的字符串,因為:比如月份中1到9月是單個數字,如果匹配到的字符串是M,就沒問題,如果匹配到的字符串是MM,要先在9前面加上一個0。所以要判斷匹配到的字符串的長度,如果是1,直接替換,否則補0。
定義一個補0的方法padLeftZero,如果str為9,補全之後為009,str長度為1,則取得字串是從抽取第二個位置到最後一個位置的字串,即09;
再舉一例:如果str為12,補全之後為0012,str長度為2,則取得字串是從抽取第二個位置到最後一個位置的字串,即12;

商品詳情頁(food組件)