1. 程式人生 > >weex專案實戰篇(二)

weex專案實戰篇(二)

本期六篇文章目錄(可點選跳轉)

1. 前言

經過前面的準備,我們終於可以開始上手weex專案了。本篇部落格主要基於最近兩週專案中用到的關於weex的知識點的整理。

2.新建weex專案

1)新建一個名為hongkong的專案,如圖所示:
這裡寫圖片描述

2 ) 輸入專案名稱
這裡寫圖片描述

3)點選【create】則專案則建立成功
這裡寫圖片描述

4)新建一個.we檔案
這裡寫圖片描述

5)新建一個home.we檔案後,專案目錄如下所示:
這裡寫圖片描述

6)為了方便參考阿里playground中的例子原始碼,我們把playground原始碼中的examples資料夾也拷貝到專案中,如下所示:
這裡寫圖片描述

7)可能你會發現我上圖還有幾個檔案目錄
image—存放圖片
include—存放公共檔案,類似做原生專案,比如title標題,每個xml都一樣,這樣我們做一個公共的,其他頁面去include進去,這個資料夾下面就是放的公共頁面。
node_modules—用到weex擴充套件元件的時候,在terminal中輸入指令,則會自動生成,後面會介紹。
weex_tmp—編譯weex檔案後,生成的資料夾,可以想象成原生的build資料夾。

3.專案需求

需要實現如下所示介面:
這裡寫圖片描述
其實很多電商公司的首頁面都是這樣的樓層佈局,我們實現出這個介面也就可以算大概會使用weex了。

剛剛拿到這個介面用weex實現的時候,很多人覺得無從下手,不是難,而是不熟悉,沒有參考demo,我這篇文章就算拋磚引玉,帶大家入門。

首先,如果讓你用原生去實現首頁,如何去做?
很簡單,用listview或者recycleview,再配合itemType,用多套itemView即可實現,那語言其實都是想通的,既然原生可以用listview去實現,那weex裡面是不是有listview控制元件,並且還有item的概念,我們通過查官方文件,果然是有的。
官方文件地址:

https://weex-project.io/cn/v-0.10/references/components/list.html
這份官方文件,希望大家做專案前,可以逛一遍,不用全部記住,至少有個大概印象,知道有哪些控制元件,如何使用,等專案中需要具體用到,再去當做工具書去查。
比如:
官方文件裡面說明,Weex 程式碼由 < template>、< style>、< script> 三個部分構成。

 <template>:必須的,使用 HTML 語法描述頁面結構,內容由多個標籤組成,不同的標籤代表不同的元件。
 <style>:可選的,使用 CSS
語法描述頁面的具體展現形式。 <script>:可選的,使用 JavaScript 描述頁面中的資料和頁面的行為,Weex 中的資料定義也在 <script> 中進行。

像上述的基本概念,必須要掌握,不然專案是進行不下去的。

4.專案實戰

下面的講解,預設官方文件粗略的瀏覽了一遍。
1)官方list例子如下所示:

<template>
  <list class="list">
    <cell class="row" repeat="item in rows" index="{{$index}}">
      <text class="item-title">row {{item.id}}</text>
    </cell>
  </list>
</template>
<style></style>
<script>
module.exports = {
  data: {
    rows:[
      {id: 1},
      {id: 2},
      {id: 3},
      {id: 4},
      {id: 5}
    ]
  }
}
</script>

在webstorm的terminal中輸入weex test.we後
這裡寫圖片描述

幾秒後,則自動開啟瀏覽器,並展現上面的效果。
這裡寫圖片描述
可見一個簡單的list已經展示出來了,接下來我們就要改造實現我們需要的效果。

2)這邊我講下我當時的思路:
1.從上向下佈局,可以看到第一行就是一個搜尋框,用到的知識點就是< text>< div>< image>,有些屬性不熟悉,可以查官方文件,佈局位置通過style慢慢調整,https://weex-project.io/cn/v-0.10/references/common-style.html這個目錄主要講解位置調整,可以詳細閱讀。
2.儘量用官方的示例來改,比如用到< img>控制元件,我們不用自己去寫,直接從官方文件,貼上下來,再做修改,避免自己書寫出現錯誤,從而真的是從入門到放棄。
3.下面的樓層佈局,就是幾個迴圈,再加上簡單的控制元件使用

3)首頁原始碼

<template>
    <div>
        <div class="header">
            <div style="flex-direction: row;align-items: center;margin-top: 18;">
                <div class="title-background" onclick="queryShops">
                    <img style="width: 30;height: 30;" src={{query}}></img>
                    <text class="title-query">搜尋商品</text>
                </div>
                <div style=" height: 36;margin-left: 30">
                    <img style="width: 36;height: 36;" src={{scan}} onclick="scanClick"></img>
                </div>
            </div>
        </div>
        <list onloadmore="onloadmore" loadmoreoffset="80">
            <refresh onpullingdown="onpullingdown" onrefresh="onrefresh" display="{{refreshDisplay}}"
                     style="width:750;flex-direction: row;justify-content: center;">
                <loading-indicator style="height:80;width:80;color:#3192e1"></loading-indicator>
            </refresh>
            <cell id="item-0" onappear="hideTop">
                <div>
                    <slider class="slider" interval="3000" auto-play="true">
                        <div class="slider-pages" repeat="item in sliderContent" onclick="sliderClick">
                            <image class="img" src="{{item.pictureUrl}}"></image>
                        </div>
                        <indicator class="indicator"></indicator>
                    </slider>
                </div>
            </cell>
            <cell repeat={{iconList}} index="{{$index}}" style="flex-direction: row;">
                <div repeat={{data}} style="flex:1;align-items:center;justify-content:center;margin-top: 37"
                     onclick="sliderClick">
                    <img style="width: 100;height: 100;" src={{icon}}></img>
                    <text class="icon-name">{{name}}</text>
                </div>
            </cell>
            <cell>
                <div style="height: 26;background-color: #ececec;margin-top: 37">
                </div>
                <div style="height: 80;">
                    <div class="wrapper">
                        <div class="countdown">
                            <img style="width:730;height: 80 " src={{countDownBackgroundUrl}}></img>
                        </div>
                        <div class="time">
                            <img style="width:40;height: 30 " src={{timeUrl}}></img>
                        </div>
                        <div class="hour">
                            <text class="time_text">{{hour_time}}</text>
                        </div>
                        <div class="hour-colon">
                            <img style="width:4;height: 18 " src={{timeIconUrl}}></img>
                        </div>
                        <div class="minute_background">
                            <img style="width:40;height: 30 " src={{timeUrl}}></img>
                        </div>
                        <div class="minute">
                            <text class="time_text">{{minute_time}}</text>
                        </div>
                        <div class="minuter-colon">
                            <img style="width:4;height: 18 " src={{timeIconUrl}}></img>
                        </div>
                        <div class="second_background">
                            <img style="width:40;height: 30 " src={{timeUrl}}></img>
                        </div>
                        <div class="second">
                            <text class="time_text">{{second_time}}</text>
                        </div>
                        <div class="arrow">
                            <img style="width:27;height:30" src={{arrowUrl}}></img>
                        </div>
                    </div>
                </div>
                <scroller scroll-direction="horizontal" style="flex-direction: row;">
                    <div repeat={{sliderhorizontal}} style="justify-content:center;margin-top:20;margin-left:30;"
                         onclick="sliderClick">
                        <img class="slider-horizontal" src={{pictureUrl}}></img>
                        <text style="margin-top: 10;font-size:24px;font-family:PingFangSC-Light;color:#000000;">{{name}}
                        </text>
                        <text style="margin-top: 7;font-size:28px;font-family:PingFangSC-Semibold;color:#ff8000;">
                            {{price}}
                        </text>
                        <text style="margin-top: 10;font-size:20px;font-family:PingFangSC-Light;color:#999999;text-decoration: line-through">
                            {{oldPrice}}
                        </text>
                    </div>
                </scroller>
                <div style="height: 20;background-color: #ececec;margin-top: 26">
                </div>
            </cell>
            <cell>
                <div style="height: 80;background-color: #ffffff;justify-content:center; align-items: center;">
                    <img style="width: 750;height: 80;" src={{list_title}}></img>
                </div>
                <div>
                    <text style="background-color:#d8d8d8;height: 1 "></text>
                </div>
            </cell>
            <cell repeat={{shops}} index="{{$index}}" style="flex-direction: row;" onclick="sliderClick">
                <div repeat={{data}}
                     style="justify-content:center;flex:1;border-bottom-width:1px;border-bottom-color: #d8d8d8;">
                    <div style="flex-direction: row;">
                        <div style="margin-bottom:32;flex:1">
                            <div style="align-items: center;justify-content:center;margin-top: 25">
                                <img class="shop-icon" src={{icon}}></img>
                            </div>
                            <text style="margin-top: 37;margin-left:20;font-size:24px;font-family:PingFangSC-Light;color:#000000;letter-spacing: 0;height: 64">
                                {{name}}
                            </text>
                            <text style="margin-top: 4;margin-left:20;font-size:32px;font-family:PingFangSC-Semibold;color:#ff8000;">
                                {{price}}
                            </text>
                        </div>
                        <div>
                            <text style="background-color:#d8d8d8;width: 1;height: 490px"></text>
                        </div>
                    </div>
                </div>
            </cell>
        </list>
        <div class="upTop" onclick="goTopClick" if={{isShowTop}}>
            <img class="gotoTop" src={{gotoTopUrl}}></img>
        </div>
    </div>
</template>

<style>
    .header {
        height: 86;
        align-items: center;
        position: sticky;
    }

    .title-background {
        align-items: center;
        justify-content: center;
        background-color: #ececec;
        border-radius: 4px;
        width: 614px;
        height: 50px;
        border-radius: 4px;
        flex-direction: row;
    }

    .title-query {
        font-size: 28;
        font-family: PingFangSC-Light;
        font-size: 28px;
        color: #333333;
        text-align: center;
    }

    .img {
        width: 750;
        height: 528;
    }

    .slider {
        flex-direction: row;
        width: 750;
        height: 528;
    }

    .slider-pages {
        flex-direction: row;
        width: 750;
        height: 528;
    }

    .indicator {
        width: 750;
        height: 528;
        position: absolute;
        top: 236;
        left: 1;
        item-color: white;
        item-selectedColor: #ffa400;
        item-size: 20;
    }

    .icon-name {
        font-family: PingFangSC-Light;
        font-size: 24px;
        color: #333333;
        text-align: center;
        margin-top: 23;
    }

    .slider-horizontal {
        background-color: #ececec;
        border-radius: 4px;
        width: 240px;
        height: 240px;
    }

    .shop-icon {
        width: 286px;
        height: 286px;
    }

    .countdown {
        align-items: center
    }

    .time {
        position: absolute;;
        top: 28;
        left: 368;
    }

    .hour {
        position: absolute;;
        top: 28;
        left: 375;
        justify-content: center;
    }

    .time_text {
        font-family: PingFangSC-Medium;
        font-size: 22px;
        color: #ffffff;
        text-align: left;
    }

    .hour-colon {
        position: absolute;;
        top: 34;
        left: 414;
        justify-content: center;
    }

    .minute_background {
        position: absolute;;
        top: 28;
        left: 426;
        justify-content: center;
    }

    .minute {
        position: absolute;;
        top: 28;
        left: 433;
        justify-content: center;
    }

    .minuter-colon {
        position: absolute;;
        top: 34;
        left: 474;
        justify-content: center;
    }

    .second_background {
        position: absolute;;
        top: 28;
        left: 486;
        justify-content: center;
    }

    .second {
        position: absolute;;
        top: 28;
        left: 493;
        justify-content: center;
    }

    .arrow {
        position: absolute;;
        top: 28;
        left: 526;
        justify-content: center;
    }

    .wrapper {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
    }

    .gotoTop {
        width: 80;
        height: 80;
    }

    .upTop {
        width: 80;
        height: 80;
        position: fixed;
        right: 20;
        bottom: 20;
    }
</style>

<script>
    var baseUrl = require('./url.js');
    var dom = require('@weex-module/dom')
    var navigator = require('@weex-module/navigator')
    var nextUrl = baseUrl.apiurl.resurl + 'search_first.js'
    var shopDetailUrl = baseUrl.apiurl.resurl + 'prodetail.js'
    var weexZxing = require('@weex-module/weex_zxing')
    module.exports = {
        data: {
            query: baseUrl.apiurl.resurl + "query.png",
            scan: baseUrl.apiurl.resurl + "scan.png",
            list_title: baseUrl.apiurl.resurl + "list_title.png",
            countDownBackgroundUrl: baseUrl.apiurl.resurl + "time_background.png",
            timeUrl: baseUrl.apiurl.resurl + "time.png",
            timeIconUrl: baseUrl.apiurl.resurl + "time_icon.png",
            arrowUrl: baseUrl.apiurl.resurl + "arrow.png",
            gotoTopUrl: baseUrl.apiurl.resurl + "goto_top.png",
            time: 0,
            hour_time: 30,
            minute_time: 40,
            second_time: 60,
            refreshDisplay: 'show',
            isShowTop: false,
            sliderContent: [
                {itemId: '520421163634', title: 'item1', pictureUrl: baseUrl.apiurl.resurl + 'slider1.png'},
                {itemId: '522076777462', title: 'item2', pictureUrl: baseUrl.apiurl.resurl + 'silder2.png'},
                {itemId: '522076777462', title: 'iten3', pictureUrl: baseUrl.apiurl.resurl + 'slider1.png'},
                {itemId: '522076777462', title: 'iten3', pictureUrl: baseUrl.apiurl.resurl + 'slider1.png'},
                {itemId: '522076777462', title: 'iten3', pictureUrl: baseUrl.apiurl.resurl + 'slider1.png'}
            ],
            iconList: [{
                data: [{name: "電視優惠", icon: baseUrl.apiurl.resurl + 'icon1.png'}, {
                    name: "冷氣優惠",
                    icon: baseUrl.apiurl.resurl + 'icon2.png'
                }, {name: "相機優惠", icon: baseUrl.apiurl.resurl + 'icon3.png'}, {
                    name: "手機優惠",
                    icon: baseUrl.apiurl.resurl + 'icon4.png'
                }]
            },
                {
                    data: [{name: "Microsoft專區", icon: baseUrl.apiurl.resurl + 'icon5.png'}, {
                        name: "Apple專區",
                        icon: baseUrl.apiurl.resurl + 'icon6.png'
                    }, {name: "促銷頻道", icon: baseUrl.apiurl.resurl + 'icon7.png'}, {
                        name: "促銷頻道",
                        icon: baseUrl.apiurl.resurl + 'icon8.png'
                    }],
                }],
            sliderhorizontal: [
                {
                    name: '華碩 (ASUS) UX1',
                    price: 'HK$2,999',
                    oldPrice: 'HK$1,999',
                    pictureUrl: baseUrl.apiurl.resurl + 'computer.png'
                },
                {
                    name: '華碩 (ASUS) UX2',
                    price: 'HK$2,999',
                    oldPrice: 'HK$1,999',
                    pictureUrl: baseUrl.apiurl.resurl + 'pad.png'
                },
                {
                    name: '華碩 (ASUS) UX3',
                    price: 'HK$2,999',
                    oldPrice: 'HK$1,999',
                    pictureUrl: baseUrl.apiurl.resurl + 'print.png'
                },
                {
                    name: '華碩 (ASUS) UX4',
                    price: 'HK$2,999',
                    oldPrice: 'HK$1,999',
                    pictureUrl: baseUrl.apiurl.resurl + 'computer.png'
                },
                {
                    name: '華碩 (ASUS) UX5',
                    price: 'HK$2,999',
                    oldPrice: 'HK$1,999',
                    pictureUrl: baseUrl.apiurl.resurl + 'pad.png'
                }
            ],
            shops: [{
                data: [{
                    name: "Apple iPhone 7 128GB",
                    icon: baseUrl.apiurl.resurl + 'nikon.png',
                    price: "HK$3,998.00"
                }, {
                    name: "三星 Galaxy J3 Pro(J3110)2+16G 皓月銀",
                    icon: baseUrl.apiurl.resurl + 'computer.png',
                    price: "HK$19,999.00"
                }]
            },
                {
                    data: [{
                        name: "Apple iPhone 7 128GB 玫瑰金色",
                        icon: baseUrl.apiurl.resurl + 'headset.png',
                        price: "HK$3,998.00"
                    }, {name: "Apple iPhone 7 128GB", icon: baseUrl.apiurl.resurl + 'pad.png', price: "HK$3,998.00"}],
                }]
        },
        created: function () {
            this.refreshDisplay = 'show'
        },
        methods: {
            queryShops: function (e) {
                var params = {'url': nextUrl, 'animated': 'true'}
                navigator.push(params, function (e) {
                    console.log('i am the callback.')
                });
            },
            scanClick: function (e) {
                weexZxing.assistant();
            },
            sliderClick: function (e) {
                var params = {'url': shopDetailUrl, 'animated': 'true'}
                navigator.push(params, function (e) {
                    console.log('i am the callback.')
                });
            },
            onrefresh: function (e) {
                this.refreshDisplay = 'show';
                this.$call('modal', 'toast', {
                    'message': '重新整理成功 ',
                    'duration': 2.0
                });
                this.refreshDisplay = 'hide'
            },
            onpullingdown: function (e) {
            },
            goTopClick: function () {
                var el = this.$el('item-0')
                dom.scrollToElement(el, {
                    offset: 0
                })
            },
            onloadmore: function (e) {
                this.isShowTop = true;
            },
            hideTop: function (e) {
                this.isShowTop = false;
            }
        },
        ready: function () {
            setInterval(function () {
                this.second_time--;
                this._app.updateActions();
            }.bind(this), 1000);
        },
    }
</script>

通過上面的佈局,則跨越實現出需求的效果。下面稍微分析下上述程式碼。

4)原始碼分析
佈局就不做過多解釋了,都是用的官方控制元件,不清楚的可以看官方介紹。主要講下一些技巧,心得跟當時遇到的一些坑。
1.公共url的抽取
最後圖片,js都部署在遠端伺服器,原生開發的時候,相信大家都會新建一個UrlUtil類來管理url,當然該類裡面肯定有個baseUrl為伺服器地址,理所應當,weex專案也可以這樣,方便維護。

如圖所示:
這裡寫圖片描述
在.w