Omi實戰-QQ附近使用者列表Web頁

【當耐特】發表於2017-02-23

寫在前面

Omi很適合大型複雜的Web頁面開發,例如一些Web線上工具的開發。但是製作這種簡單的QQ附近使用者列表Web頁,也不會有大炮哄蚊子的感覺。

專案開始之前,實現選擇一個腳手架。可以使用omi-cli快速建立專案腳手架。腳手架主要基於 Gulp + Webpack + Babel + BrowserSync 進行開發和部署。

Gulp用來串聯整個流程,Webpack + Babel讓你可以寫ES6和打包,BrowserSync用來幫你刷瀏覽器,不用F5了。

這裡需要注意的是,BrowserSync會啟動localhost:3000導致你的AJAX請求跨域而無法拿到資料。

Omi實戰-QQ附近使用者列表Web頁

所以,要使用Fiddler並配置Extention:

Omi實戰-QQ附近使用者列表Web頁

目錄

Omi實戰-QQ附近使用者列表Web頁

目錄結構也是和Omi Github上的scaffolding一樣。
元件全放在component目錄,公共的工具庫放在common,其他資原始檔放在asset裡。

命令

開發

npm run dev

釋出

npm run dist

開始寫碼

萬事具備,開始寫碼。先寫元件:

import Omi from 'omi'

class UserList extends Omi.Component {
    constructor(data) {
        super(data)
    }

    install() {
        this.data.uin_info || (this.data.uin_info = [])
        this.data.uin_info.forEach(user => {
            this.prepareData(user)
        })
    }
    
    prepareData(user){
        user.desc_d = user.desc.split(" ")[0]
        user.desc_t = user.desc.split(" ")[1]
        user.isBoy = user.sex === "男"
        user.qlogo = user.url.replace("http://", location.protocol + "//").replace(/&/g, "&")
        if (user.profession_desc) {
            user.hasProfession_desc = true
        }
    }
    
    appendUsers (users) {
        users.uin_info && users.uin_info.forEach(user =>{
            this.prepareData(user)
            this.data.uin_info.push(user)
        })
        this.update()
    }

    sendGift(uin, nick, qlogo) {
        //送禮物並關閉webview,此處省略
        //..
        //..
    }

    render() {
        return `
<div class="user_list">
    {{#uin_info}}
    <div class="item" onclick="sendGift('{{uin}}','{{nick}}','{{qlogo}}')">
        <div class="qlogo">
            <img style="width: 70px;" src="{{qlogo}}" />
        </div>
        <div class="main b1 bb">
            <div class="nick">{{{nick}}}</div>
            <div class="icons">
                {{#isBoy}}<span class="boy_age"><img src="component/user_list/boy.png" alt="" /><span>{{age}}</span></span> {{/isBoy}}
               {{^isBoy}}<span class="girl_age"><img src="component/user_list/girl.png" alt="" /><span>{{age}}</span></span> {{/isBoy}}
                {{#hasProfession_desc}} <span class="profession"><span>{{profession_desc}}</span></span> {{/hasProfession_desc}}
            </div>
            <div class="action">{{{intro}}}</div>
        </div>
        <div class="distance_info">{{desc_d}} · {{desc_t}}</div>
    </div>
    {{/uin_info}}
    <div style="text-align:center;font-size:13px;line-height:30px;height:30px;"><span class="loading"></span> 載入中...</div>
</div>
`
    }

    style() {
        return `


.qlogo {
    overflow: hidden;
    width: 70px;
    height: 70px;
    -webkit-border-radius: 50%;
    border-radius: 50%;
    position: absolute;
    top: 10px;
    left: 12px;
}
...
...
..這裡省略大量.....
...
...

.distance_info {
    position: absolute;
    top: 15px;
    right: 9px;
    color: #7B7B84;
    font-size: 10px;
}

        `
    }
}

export default UserList

元件裡面有5個方法:

  • constructor 元件的建構函式,生命週期的一部分,其實在super上面和super呼叫下面可以對data做一些處理。super之上不能拿到this
  • install 元件的初始化安裝,生命週期的一部分,這裡也可以拿到使用者傳進的data進行處理
  • prepareData 對資料進行一些處理來滿足模板的渲染
  • appendUsers 新增資料,用來處理使用者向下滾動的load more 的行為的時候呼叫
  • sendGift 送禮物,點選每一項的時候會有送禮物的行為,業務相關,可以無視..

其他兩個方法的render和style用來生成元件的HTML和區域性CSS,不再敘述。
render裡面使用了mustache.js模板引擎;
如果使用omi.lite.js版本(不包含mustache.js模板引擎)的話,你也可以使用ES6 map去遍歷資料生成HTML,或者重寫 Omi.template去使用任意你喜歡的模板引擎,非常靈活方便。

這裡友情提醒一下,如果使用webstorm的話,可以把js version設定成JSX Harmony或者ECMAScript 6,這樣才是寫ES6+的姿勢。

Omi實戰-QQ附近使用者列表Web頁

下面來看index.js:

import Root from './config.js'
import Omi from 'omi'
import UserList from '../component/user_list/index.js'

Omi.makeHTML('UserList', UserList)

class Main extends Omi.Component {
    constructor(data) {
        super(data)
    }

    installed() {
        window.onscroll = () => this.loadMore()
        this.requestData(data => this.list.appendUsers(data))
    }

    loadMore() {
        const body = document.body,
            html = document.documentElement,
            height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
            vp_height = window.innerHeight

        if (height - document.body.scrollTop - vp_height < 200) {
            this.requestData(data => this.list.appendUsers(data))
        }
    }

    requestData(callback) {
        if (Root.isDev) {
            require.ensure([], ()=> {
                callback(require('./mock_data.js').default)
            })
        }else{
            //ajax 請求資料,這裡省略
        }
    }

    render() {
        return `
    <div class="main">
        <UserList name="list" />
    </div>`
    }
}

Omi.render(new Main(),'body')

通過Omi.makeHTML('UserList', UserList)這句程式碼,UserList變成了可以巢狀至render方法中的標籤。如:

 render() {
        return `
    <div class="main">
        <UserList name="list" />
    </div>`
    }

下面這行程式碼,是監聽滾動,快滾動到底部的時候在loadMore裡面會去請求。

window.onscroll = () => this.loadMore()

通過height - document.body.scrollTop - vp_height < 200判斷使用者快要滾動底部,滾動到底部有個載入更多的行為,即:

if (height - document.body.scrollTop - vp_height < 200) {
    this.requestData(data => this.list.appendUsers(data))
}

requestData是去伺服器請求分頁的資料,請求成功,會去呼叫this.list.appendUsers進行資料的新增。
慢著?this.list哪裡來的?appendUsers又是哪裡定義的方法?且看下面:

 <UserList name="list" />

上面標記的name,讓你可以直接通過this.list訪問到UserList物件的例項,所以也就可以呼叫它的appendUsers方法!

再來看下資料模擬:

if (Root.isDev) {
        require.ensure([], ()=> {
            callback(require('./mock_data.js').default)
        })
    }

這裡在dev環境下是mock資料,使用了require.ensure,這樣當你npm run dist的時候,mock的資料就不會被打包進js裡了!!

最後

好了,就這麼多,Omi讓程式碼真心方便簡潔~~~

相關地址

招募計劃

Omi實戰-QQ附近使用者列表Web頁

相關文章