快速入門 WePY 小程序 原 薦

一、WePY介紹

WePY 是 騰訊 參考了Vue 等框架對原生小程序進行再次封裝的框架,更貼近於 MVVM 架構模式, 並支持ES6/7的一些新特性。

二、WePY 使用

1、WePY的安裝或更新都通過npm進行:

npm install -g wepy-cli  //全局安裝或更新WePY命令行工具(wepy腳手架): wepy-cli
wepy -v //查看wepy-cli版本
wepy init standard <projectName> //新建wepy小程序項目,1.7.0之前的版本使用:wepy new myproject
wepy list //查看項目模板
cd <projectName> //切換至項目目錄
npm  install //安裝依賴
wepy build --watch //開啓實時編譯

git base here:

(1)全局安裝或更新 wepy-cli:

(2)查看 wepy-cli 版本:

(3)創建 wepy 小程序項目:

(4)切換至項目目錄,安裝依賴:

(5)開啓實時編譯

2、代碼高亮WebStorm/PhpStorm(其他工具參見wepy官網代碼高亮

(1)打開Settings,搜索Plugins,搜索Vue.js插件並安裝。

(2) 打開Settings,搜索File Types,找到Vue.js Template,在Registered Patterns添加*.wpy,即可高亮。

3、代碼優化

(1)代碼規範

  • wepy標籤和原生一樣
  • 自定義組件命名應避開:原生組件名(input、button、view、repeat等)、WePY的輔助標籤<repeat>
  • 變量/方法名儘量使用駝峯式命名,避免使用$開頭($開頭的標識符是WePY內建屬性/方法,可在js中以this.的方式直接使用,具體請參考API文檔
  • app、pages、components文件名的後綴爲.wpy,外鏈的文件可以是其它後綴。 具體請參考wpy文件說明
  • 支持ES6/7的一些新特性,框架在ES6(ECMAScript 6)下開發(默認使用babel編譯),因此也需要使用ES6開發小程序,ES6中有大量的語法糖可以讓我們的代碼更加簡潔高效。
  • wepy繼承了wx對象的方法,建議在wepy框架開發中不要用到wx對象的方法,雖然運行時效果是一樣,但是打包時會cli報錯(wepy中沒有wx對象)wepy中組件中使用的是class,vue中使用的的是對象。

(2)數據綁定

小程序頁面渲染層和JS邏輯層分開的,setData操作實際就是JS邏輯層與頁面渲染層之間的通信,在同一次運行週期內多次執行setData操作時,通信的次數是一次還是多次取決於API本身的設計。WePY使用髒數據檢查對setData進行封裝,在函數運行週期結束時執行髒數據檢查,一來可以不用關心頁面多次setData是否會有性能上的問題,二來可以更加簡潔去修改數據實現綁定,不用重複去寫setData方法。

//原生小程序
this.setData({title: 'this is title'});//通過Page提供的setData方法來綁定數據

//wepy
this.title = 'this is title';


//wepy 在異步函數中更新數據的時候,必須手動調用$apply方法,纔會觸發髒數據檢查流程的運行
setTimeout(() => {
    this.title = 'this is title';
    this.$apply();
}, 3000)


//保留setData方法,但不建議使用setData執行綁定,修復傳入undefined的bug,並且修改入參支持: 
this.setData(target, value) 
this.setData(object)

(3)事件綁定以及傳參優化

<view @tap="click"></view> //​​​​​ 原 bindtap="click"(省略了.default後綴 )綁定小程序冒泡型事件
<view @tap.stop="click"></view> //​​​​​ 原catchtap="click"  綁定小程序捕獲型事件,如catchtap
<view @tap.capture="click"></view> //​​​​​ 原 capture-bind:tap="click"
<view @tap.capture.stop="click"></view> //​​​​​ 原 capture-catch:tap="click"
<!--事件傳參-->
<view @tap="click({{index}})"></view> //​​​​​ 原bindtap="click" data-index={{index}}

(4)框架默認對小程序提供的API全都進行了 Promise 處理,甚至可以直接使用async/await等新特性進行開發,同時修復了一些原生API的缺陷(如:wx.request的併發問題等)

// 原生代碼:

wx.request({
    url: 'xxx',
    success: function (data) {
        console.log(data);
    }
});

// WePY 使用方式, 需要開啓 Promise 支持,參考開發規範章節
wepy.request('xxxx').then((d) => console.log(d));

// async/await 的使用方式, 需要開啓 Promise 和 async/await 支持,參考 WIKI
async function request () {
   let d = await wepy.request('xxxxx');
   console.log(d);
}

(5)computed 計算屬性computed計算屬性(類型{ [key: string]: Function }),是一個有返回值的函數,可直接被當作綁定數據來使用,類似於data屬性。需要注意的是,只要是組件中有任何數據發生了改變,那麼所有計算屬性就都會被重新計算。

  data = {
      a: 1
  }

  // 計算屬性aPlus,在腳本中可通過this.aPlus來引用,在模板中可通過{{ aPlus }}來插值
  computed = {
      aPlus () {
          return this.a + 1
      }
  }

(6)watcher 監聽器

通過監聽器watcher(類型{ [key: string]: Function })能夠監聽到任何屬性的更新。監聽器適用於當屬性改變時需要進行某些額外處理的情形。

  data = {
      num: 1
  }

  // 監聽器函數名必須跟需要被監聽的data對象中的屬性num同名,
  // 其參數中的newValue爲屬性改變後的新值,oldValue爲改變前的舊值
  watch = {
      num (newValue, oldValue) {
          console.log(`num value: ${oldValue} -> ${newValue}`)
      }
  }

  // 每當被監聽的屬性num改變一次,對應的同名監聽器函數num()就被自動調用執行一次
  onLoad () {
      setInterval(() => {
          this.num++;
          this.$apply();
      }, 1000)
  }

(7)WXS (WeiXin Script)

WePY 從1.7.x 版本開始支持 wxs 語法,但語法與原生 wxs 稍有出入

①wxs是基於原生的wxs去實現的,只是通過編譯把現在的語法編譯爲原生語法

②wxs必須是外鏈文件。並且後綴爲.wxs

③wxs引入後只能在template中使用,不能在script中使用

/**
project
└── src
    ├── wxs
    |   └── mywxs.wxs      wxs 文件 
    ├── pages
    |   └── index.wpy      頁面
    └──app.wpy           
**/

// mywxs.wxs

module.exports = {
  text: 'This is from wxs',
  filter: function (num) {
    return num.toFixed(2);
  }
};

// index.wpy

<template>
  <text>{{m1.text}}</text>
  <text>{{m1.filter(num)}}</text>
</template>

<script>
  import wepy from 'wepy';
  import mywxs from '../wxs/mywxs.wxs';

  export default class Index extends wepy.page {

    data = {
      num: 10
    };

    wxs = {
      m1: mywxs
    }

  };
</script>

(8)interceptor 攔截器

可以使用WePY提供的全局攔截器對原生API的請求進行攔截。具體方法是配置API的config、fail、success、complete回調函數。參考示例:

import wepy from 'wepy';

export default class extends wepy.app {
    constructor () {
        // this is not allowed before super()
        super();
        // 攔截request請求
        this.intercept('request', {
            // 發出請求時的回調函數
            config (p) {
                // 對所有request請求中的OBJECT參數對象統一附加時間戳屬性
                p.timestamp = +new Date();
                console.log('config request: ', p);
                // 必須返回OBJECT參數對象,否則無法發送請求到服務端
                return p;
            },

            // 請求成功後的回調函數
            success (p) {
                // 可以在這裏對收到的響應數據對象進行加工處理
                console.log('request success: ', p);
                // 必須返回響應數據對象,否則後續無法對響應數據進行處理
                return p;
            },

            //請求失敗後的回調函數
            fail (p) {
                console.log('request fail: ', p);
                // 必須返回響應數據對象,否則後續無法對響應數據進行處理
                return p;
            },

            // 請求完成時的回調函數(請求成功或失敗都會被執行)
            complete (p) {
                console.log('request complete: ', p);
            }
        });
    }
}

三、WePY項目的目錄結構

dist目錄爲WePY通過build指令生成的目錄,除額外增加的npm目錄外,其目錄結構與原生小程序的目錄結構類似。

原生小程序:app(app.jsapp.jsonapp.wxss),page(page.jspage.jsonpage.wxmlpage.wxss),文件必須同名。WePY中則使用了單文件模式:app.wpypage.wpy

 ==> 

一個.wpy文件可分爲三大部分,各自對應於一個標籤:

  1. 腳本<script>部分,又可分爲兩個部分:

    邏輯部分,除了config對象之外的部分,對應於原生的.js文件

    配置部分,即config對象,對應於原生的.json文件

  1. 結構<template>部分,對應於原生的.wxml文件

  2. 樣式<style>部分,對應於原生的.wxss文件

<!--lang決定了其代碼編譯過程,src決定是否外聯代碼,存在src屬性且有效時,會忽略內聯代碼-->
<style lang="less" src="page1.less"></style>//lang值:css(默認)、less、scss、stylus、postcss
<template lang="wxml" src="page1.wxml"></template>//lang值:wxml(默認)、xml、pug(原jade)。入口文件app.wpy不需要template,所以編譯時會被忽略。
<script></script>//lang值:babel(默認、TypeScript

主要對目錄的以下幾點分析(其他目錄文件詳解類似於https://my.oschina.net/wangnian/blog/2050375中做的分析):

1、src文件夾

(1)components組件:

組件實例繼承自wepy.component類,除了不需要config配置以及頁面特有的一些生命週期函數之外,其屬性與頁面屬性大致相同:

import wepy from 'wepy';

export default class MyComponent extends wepy.component {
    props = {}//接收父組件傳來的參數
    customData = {}  // 自定義數據
    customFunction () {}  //自定義方法
    onLoad () {}  // 在Page和Component共用的生命週期函數
    data = {};  // 頁面所需數據均需在這裏聲明,可用於模板數據綁定
    components = {};  // 聲明頁面中所引用的組件,或聲明組件中所引用的子組件
    mixins = [];  // 聲明頁面所引用的Mixin實例
    computed = {};  // 聲明計算屬性(詳見後文介紹)
    watch = {};  // 聲明數據watcher(詳見後文介紹)
    methods = {};  // 聲明頁面wxml中標籤的事件處理函數。注意,此處只用於聲明頁面wxml中標籤的bind、catch事件,自定義方法需以自定義方法的方式聲明
    events = {};  // WePY組件事件處理函數對象,存放響應組件之間通過$broadcast、$emit、$invoke所傳遞的事件的函數
}
/** 與page不同的是component不存在:
    onShow () {}  // 只在Page中存在的頁面生命週期函數
    config = {};  // 只在Page實例中存在的配置數據,對應於原生的page.json文件,類似於app.wpy中的config
    onReady() {}  //  只在Page中存在的頁面生命週期函數
**/

原生小程序支持js模塊化,但彼此獨立,業務代碼與交互事件仍需在頁面處理。無法實現組件化的鬆耦合與複用(如,模板A中綁定一個bindtap="myclick",模板B中同樣綁定一樣bindtap="myclick",那麼就會影響同一個頁面事件、數據)

WePY組件的所有業務與功能在組件本身實現,組件與組件之間彼此隔離(上述例子在WePY的組件化開發過程中,A組件只會影響到A所綁定的myclick,B也如此)

// 原生代碼:

<!-- item.wxml -->
<template name="item">
  <text>{{text}}</text>
</template>

<!-- index.wxml -->
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>

<!-- index.js -->
var item = require('item.js')




// WePY
<!-- /components/item.wpy -->
 <text>{{text}}</text>

<!-- index.wpy -->
<template>
    <com></com>
</template>
<script>
    import wepy from 'wepy';
    import Item from '../components/item';
    export default class Index extends wepy.page {
        components = { com: Item }
    }
</script>

ps,在 1.7.2-alpha4 的實驗版本中提供了對原生組件的支持

①引用組件

頁面可以引入組件,而組件還可以引入子組件

/**
project
└── src
    ├── components
    |   └── child.wpy
    ├── pages
    |   ├── index.wpy    index 頁面配置、結構、樣式、邏輯
    |   └── log.wpy      log 頁面配置、結構、樣式、邏輯
    └──app.wpy           小程序配置項(全局公共配置、公共樣式、聲明鉤子等)
**/

// index.wpy

<template>
    <!-- 以`<script>`腳本部分中所聲明的組件ID爲名命名自定義標籤,從而在`<template>`模板部分中插入組件 -->
   <view class="child1">
        <child></child>
    </view>

    <view class="child2">
<!--注意:WePY中,在父組件template模板部分插入駝峯式命名的子組件標籤時,不能將駝峯式命名轉換成短橫杆式命名(比如將childCom轉換成child-com,這與Vue中不一致)-->
        <anotherchild></anotherchild>
    </view>
</template>

<script>
    import wepy from 'wepy';
    //引入組件文件
    import Child from '../components/child';

    export default class Index extends wepy.component {
        //聲明組件,分配組件id爲child,需要注意的是,WePY中的組件都是靜態組件,是以組件ID作爲唯一標識的,每一個ID都對應一個組件實例,當頁面引入兩個相同ID的組件時,這兩個組件共用同一個實例與數據,當其中一個組件數據變化時,另外一個也會一起變化。
        components = {
            //爲兩個相同組件的不同實例分配不同的組件ID,從而避免數據同步變化的問題
            child: Child,
            anotherchild: Child
        };
    }
</script>

②循環渲染組件(1.4.6新增

WePY 1.x 版本中,循環渲染WePY組件時(類似於通過wx:for循環渲染原生的wxml標籤),必須使用WePY定義的輔助標籤<repeat>

WePY組件是靜態編譯組件(在編譯階段編譯進頁面),每個組件都是唯一的一個實例,目前只提供簡單的 repeat 支持(不支持在 repeat 的組件中去使用 propscomputedwatch 等),因此如下:

<!-- 錯誤使用 --->
// list.wpy
<view>{{test.name}}</view>

// index.wpy
<repeat for="{{mylist}}">
   <List :test.sync="item"></List>
</repeat>

<!-- 推薦用法 --->
// list.wpy
<repeat for="{{mylist}}">
    <view>{{item.name}}</view>
</repeat>

// index.wpy
<List :mylist.sync="mylist"></List>

③props 傳值

props傳值在WePY中屬於父子組件之間傳值的一種機制,包括靜態傳值與動態傳值。

靜態傳值爲父組件向子組件傳遞常量數據,因此只能傳遞String字符串類型

動態傳值是指父組件向子組件傳遞動態數據內容,父子組件數據完全獨立互不干擾。但可以通過使用.sync修飾符來達到父組件數據綁定至子組件的效果,也可以通過設置子組件props的twoWay: true來達到子組件數據綁定至父組件的效果。如果既使用.sync修飾符,同時子組件props中添加的twoWay: true時,就可以實現數據的雙向綁定。

// parent.wpy

<!--在父組件template模板部分所插入的子組件標籤中,使用:prop屬性(等價於Vue中的v-bind:prop屬性)來進行動態傳值-->
<child :title="parentTitle" :syncTitle.sync="parentTitle" :twoWayTitle="parentTitle"></child>
<!--通過使用.sync修飾符來達到父組件數據綁定至子組件的效果-->
<script>
data = {
    parentTitle: 'p-title'
};
</script>

// child.wpy

<script>
props = {
    // 靜態傳值
    title: String,

    // 父向子單向動態傳值
    syncTitle: {
        type: String,
        default: 'null'
    },
   // 雙向綁定
    twoWayTitle: {
        type: String,
        default: 'nothing',
        twoWay: true//twoWay: true(默認false)來達到子組件數據綁定至父組件的效果,如果同時使用.sync修飾符,就可以實現雙向綁定
    }
};

onLoad () {
    console.log(this.title); // p-title
    console.log(this.syncTitle); // p-title
    console.log(this.twoWayTitle); // p-title

    this.title = 'c-title';
    console.log(this.$parent.parentTitle); // p-title.
    this.twoWayTitle = 'two-way-title';
    this.$apply();
    console.log(this.$parent.parentTitle); // two-way-title.  --- twoWay爲true時,子組件props中的屬性值改變時,會同時改變父組件對應的值
    this.$parent.parentTitle = 'p-title-changed';
    this.$parent.$apply();
    console.log(this.title); // 'c-title';
    console.log(this.syncTitle); // 'p-title-changed' --- 有.sync修飾符的props屬性值,當在父組件中改變時,會同時改變子組件對應的值。
}
</script>

④組件通信與交互

wepy.component基類提供$broadcast$emit$invoke三個方法用於組件之間的通信和交互:

$broadcast

$broadcast事件是由父組件發起,所有子組件都會收到此廣播事件,除非事件被手動取消。事件廣播的順序爲廣度優先搜索順序

$emit

$emit$broadcast正好相反,組件發起事件後所有祖先組件會依次接收到$emit事件

//子組件:
this.$emit('some-event', 1, 2, 3, 4);

//父組件:
import wepy from 'wepy'

export default class Com extends wepy.component {
    components = {};

    data = {};

    methods = {};

    // events對象中所聲明的函數爲用於監聽組件之間的通信與交互事件的事件處理函數
    events = {
        'some-event': (p1, p2, p3, $event) => {
               console.log(`${this.$name} receive ${$event.name} from ${$event.source.$name}`);
        }
    };
    // Other properties
}

$invoke

$invoke是一個頁面/組件對另一個組件中的方法的直接調用,通過傳入組件路徑找到相應的組件,然後再調用其方法。

this.$invoke('ComA', 'someMethod', 'someArgs');//在頁面Page_Index中調用組件ComA的某個方法
this.$invoke('./../ComB/ComG', 'someMethod', 'someArgs');//在組件ComA中調用組件ComG的某個方法
//只能在methods中使用  在周期函數使用會報錯

⑤組件自定義事件處理函數(.user事件後綴,1.4.8新增

示例如下(注意,如果用了自定義事件,則events中對應的監聽函數不會再執行):

// index.wpy

<template>
    <child @childFn.user="parentFn"></child>
</template>

<script>
    import wepy from 'wepy'
    import Child from '../components/child'

    export default class Index extends wepy.page {
        components = {
            child: Child
        }

        methods = {
            parentFn (num, evt) {
                console.log('parent received emit event, number is: ' + num)
            }
        }
    }
</script>


// child.wpy

<template>
    <view @tap="tap">Click me</view>
</template>

<script>
    import wepy from 'wepy'

    export default class Child extends wepy.component {
        methods = {
            tap () {
                console.log('child is clicked')
                this.$emit('childFn', 100)
            }
        }
    }
</script>

⑥slot 組件內容分發插槽

WePY中的slot插槽作爲內容分發標籤的空間佔位標籤,便於在父組件中通過對相當於擴展板卡的內容分發標籤的“插拔”,更爲靈活、方便地對子組件進行內容分發。

注意,父組件中的標籤必須有slot屬性,且值爲子組件中對應的slot名,這樣父組件內容分發標籤中的內容(即便沒有內容,子組件插槽中的默認內容也不會顯示出來,只有刪除了父組件中對應的內容分發標籤,才能顯示出來)會覆蓋掉子組件對應插槽中的默認內容

//首先在子組件template模板部分中聲明slot標籤作爲內容插槽,同時必須在其name屬性中指定插槽名稱,還可設置默認的標籤內容
<view class="panel">
    <slot name="title">默認標題</slot>
    <slot name="content">默認內容</slot>
</view>

//然後在引入了該帶有插槽的子組件的父組件template模板部分中聲明用於“插拔”的內容分發標籤
<panel>
    <view slot="title">新的標題</view>
    <view slot="content">
        <text>新的內容</text>
    </view>
</panel>

eg:message-com.wpy:

<template>
<!-- 1.4.6新增:循環渲染時(類似於原生的wx:for),必須使用WePY定義的輔助標籤"<repeat>" -->
  <repeat for="{{messageList}}" index="index" item="message">
    <navigator url="/pages/topicDetail?topicId={{message.busiId}}">
      <view class="msgList">
        <!-- "<text selectable='true'>" 使文字可選-->
        <text selectable='true'>{{message.content}}</text>
        <view style="text-align: right;">
          <text style="color: rgb(202,202,202);">{{message.createTime}}</text>
        </view>
      </view>
    </navigator>
  </repeat>
</template>
<script>
  import wepy from 'wepy' //引入wepy

  export default class Message extends wepy.component {//創建組件實例
    props = {//接收父組件參數
      messageList: {// * 類型和默認值參數不能省略,組件會偶發性接收不到父組件傳遞的參數
        type: Array,
        default:[]
      }
    };
  }
</script>
<style scoped lang="less">

  .topicInfo text {
    font-size: 12px;
    color: #666;
  }

  .topicBottom view {
    margin-right: 15px;
  }

  .msgList {
    background-color: #fff;
    margin-top: 7px;
    padding: 10px 15px;
  }

</style>

 message-page.wpy:

<template>
  <view wx:if="{{!messageList.length}}" class="noData">暫無消息</view>
  <block wx:else>
    <message :messageList.sync="messageList"></message>
    <downLoad :show.sync="getListParam"></downLoad>
  </block>
</template>

<script>
  import wepy from 'wepy'
  import Message from '../components/message'
  import DownLoad from '../components/downLoad'
  import listMixin from '../mixins/list'
  import {connect} from 'wepy-redux'
  import {getMessageList} from '../store/actions'

  @connect({
    messageList(state) {
      return state.reducer.messageList;
    }
  }, {
    getMessageList
  })

  export default class MineMessages extends wepy.page {
    config = {
      navigationBarTitleText: '我的消息'
    };
    components = {
      message: Message,
      downLoad: DownLoad
    };

    data = {};
    mixins = [listMixin];

    methods = {
      getList(params) {
        let listParam = {
          messageType: 4
        };
        if (wx.getStorageSync('userId')) {
          this.getMessageList(Object.assign(listParam, params));
        } else {
          wx.showToast({
            title: '您還沒有登錄',
            icon: 'none'
          });
        }
      }
    };
  }
</script>

(2)mixins:Mixin 混合(公用的js)

混合可以將組件之間的可複用部分抽離,從而在組件中使用混合時,可以將混合的數據,事件以及方法注入到組件之中。混合分爲兩種:

  • 默認式混合(data、components、events、自定義方法),即組件未聲明的選項將混合對象中注入組件之中,組件已聲明的選項將不受影響
  • 兼容式混合(methods響應事件 小程序頁面事件),即先響應組件本身響應事件,然後再響應混合對象中響應事件(Vue則相反,先執行mixin中的函數, 再執行組件本身的函數

eg:listMixin.js:

import wepy from 'wepy'

export default class ListMixin extends wepy.mixin {//創建mixin實例
  config = {
    enablePullDownRefresh: true,//開啓下拉刷新,默認是關閉的
    onReachBottomDistance: 10,//設置觸發下拉刷新的底部距離
    backgroundColor: "#eab010"//設置背景色
  };
  data = {
    getListParam: {//獲取列表數據的通用參數
      hasMoreData: true,
      loading: false,
      noMore: false,
      page: 1,
      limit: 10,
    }
  };

  /**
   * 頁面相關事件處理函數--監聽用戶下拉動作(下拉刷新)
   */
  onPullDownRefresh() {
    wx.showNavigationBarLoading(); //在標題欄中顯示加載
    this.data.getListParam.page = 1;//下拉刷新時參數page=1
    this.methods.getList(this.data.getListParam);//調用組件中的獲取列表函數
    setTimeout(() => {
      wx.hideNavigationBarLoading(); //完成停止加載
      wx.stopPullDownRefresh(); //停止下拉刷新
    }, 300)
  };

  /**
   * 頁面上拉觸底事件的處理函數(上拉加載)
   */
  onReachBottom() {
    if (this.data.getListParam.hasMoreData) {
      this.data.getListParam.page++;//每觸發一次page++
      this.data.getListParam.hasMoreData = false;//關閉可調用函數
      this.data.getListParam.loading = true;//顯示加載中...(自己寫的底部加載中樣式的組件)
      this.methods.getList(this.data.getListParam);//調用組件中的獲取列表函數
      setTimeout(() => {
        this.data.getListParam.loading = false;//關閉顯示加載中...(自己寫的底部加載中樣式的組件)
        this.$apply();//強制渲染
      }, 100);
    } else {
      this.data.getListParam.noMore = true;//顯示加載完成(自己寫的底部加載到底樣式的組件)
    }
  };

  onReady() {
    this.methods.getList(this.data.getListParam);//初始化請求頁面數據
  }

}

使用時引入然後注入到組件實例(最好放在data屬性後,否則會偶發性報錯),eg:

(3)頁面page.wpy

Page頁面實際上繼承自Component組件,即Page也是組件。除擴展了頁面所特有的config配置以及特有的頁面生命週期函數之外,其它屬性和方法與Component一致:

import wepy from 'wepy';

export default class MyPage extends wepy.page {
    customData = {}  // 自定義數據

    customFunction () {}  //自定義方法

    onLoad () {}  // 在Page和Component共用的生命週期函數

    onUnload() {}  // 監聽頁面卸載

    onReady() {}  //  只在Page中存在的頁面生命週期函數

    onShow () {}  // 只在Page中存在的頁面生命週期函數,當小程序啓動,或從後臺進入前臺顯示

    onHide() {}  // 只在Page中存在的頁面生命週期函數,當小程序從前臺進入後臺

    config = {};  // 只在Page實例中存在的配置數據,對應於原生的page.json文件,類似於app.wpy中的config

    data = {};  // 頁面所需數據均需在這裏聲明,可用於模板數據綁定

    components = {};  // 聲明頁面中所引用的組件,或聲明組件中所引用的子組件

    mixins = [];  // 聲明頁面所引用的Mixin實例

    computed = {};  // 聲明計算屬性(詳見後文介紹)

    watch = {};  // 聲明數據watcher(詳見後文介紹)

    methods = {};  // 聲明頁面wxml中標籤的事件處理函數。注意,此處只用於聲明頁面wxml中標籤的bind、catch事件,自定義方法需以自定義方法的方式聲明

    events = {};  // WePY組件事件處理函數對象,存放響應組件之間通過$broadcast、$emit、$invoke所傳遞的事件的函數

    onPullDownRefresh(){}  // 監聽用戶下拉動作

    onReachBottom(){}  // 頁面上拉觸底事件的處理函數

    onShareAppMessage(){}  // 用戶點擊右上角分享

    onPageScroll(){}  // 頁面滾動

    onTabItemTap(){}  //  當前是 tab 頁時,點擊 tab 時觸發 
}

(4)狀態管理store(redux)

(5)app.wpy:小程序入口

app.wpy實例繼承自wepy.app類,包含:config配置對象(對應原生的app.json文件,build編譯時會根據config屬性自動生成app.json文件)、globalData全局數據對象、自定義方法與屬性、小程序生命週期函數。

在Page頁面實例中,可以通過this.$parent來訪問App實例。

<script>
import wepy from 'wepy';
export default class extends wepy.app {
    config = {
        pages:[// pages定義當前小程序所有頁面路徑,讓微信客戶端知道當前你的小程序頁面定義在哪個目錄
            'pages/index',
            'pages/mine'
        ],
        window:{//window定義小程序所有頁面的頂部背景顏色,文字顏色定義等。
            "backgroundTextStyle": "light",
            "navigationBarBackgroundColor": "#fff",
            "navigationBarTitleText": "頂部標題",
            "navigationBarTextStyle": "black"
        },
        tabBar: {
            selectedColor: '#ea9100',//底部導航字體選中時的顏色
            list: [
                   {
                     pagePath: 'pages/index',//導航頁面路徑(必須在pages中定義)
                     text: '首頁',//導航名
                     iconPath: 'img/index.png',//未選中的導航icon
                     selectedIconPath: 'img/index1.png'//選中時的導航icon
                   },
                   {
                     pagePath: 'pages/mine',
                     text: '我的',
                     iconPath: 'img/mine.png',
                     selectedIconPath: 'img/mine1.png'
                    }
            ]
       },
    };
    onLaunch() {//初始化
        console.log(this);
    }

    onShow(){}//當小程序啓動,或從後臺進入前臺顯示
    onHide(){}//當小程序從前臺進入後臺
}
</script>

<style lang="less">
/** less **/
</style>

(6)index.template.html:web頁面的入口文件

2、project.config.json小程序項目配置文件

1.7.0 之後的版本會在根目錄包含project.config.json,使用微信開發者工具-->添加項目項目目錄請選擇項目根目錄即可根據配置完成項目信息自動配置。

1.7.0 之前生成的代碼包可能不存在project.config.json文件,建議手動創建該文件後再添加項目。project.config.json文件內容如下:

{
  "description": "project description",
  "setting": {
    "urlCheck": true,//對應不檢查安全域名選項,開啓。 如果已配置好安全域名則建議關閉
    "es6": false,//對應關閉ES6轉ES5選項,關閉。 重要:未關閉會運行報錯
    "postcss": false,//對應關閉上傳代碼時樣式自動補全選項,關閉。 重要:某些情況下漏掉此項也會運行報錯
    "minified": false //對應關閉代碼壓縮上傳選項,關閉。重要:開啓後,會導致真機computed, props.sync 等等屬性失效。(注:壓縮功能可使用WePY提供的build指令代替)
  },
  "compileType": "miniprogram",
  "appid": "touristappid",
  "projectname": "Project name",
  "miniprogramRoot": "./dist"
}

3、wepy.config.js

const path = require('path');
var prod = process.env.NODE_ENV === 'production';

module.exports = {
  /*wpyExt:缺省值爲'.wpy',IDE默認情況下不會對此文件類型進行高亮處理
    除了進行前文代碼高亮設置之外
    還可以直接將相關文件的後綴名由.wpy修改爲.vue,然後將此選項修改爲.vue
  */
  wpyExt: '.wpy',
  eslint: false,
  cliLogs: !prod,
  build: {
    web: {
      htmlTemplate: path.join('src', 'index.template.html'),
      htmlOutput: path.join('web', 'index.html'),
      jsOutput: path.join('web', 'index.js')
    }
  },
  resolve: {
    alias: {
      counter: path.join(__dirname, 'src/components/counter'),
      '@': path.join(__dirname, 'src')
    },
    aliasFields: ['wepy', 'weapp'],
    modules: ['node_modules']
  },
  /** compilers爲1.3.1版本之後的功能,如果需要使用其它語法,請先配置compilers,然後再安裝相應的compilers
     目前支持wepy-compiler-less, wepy-compiler-postcss,wepy-compiler-sass、wepy-compiler-babel、wepy-compiler-pug
     其他compiler持續開發中
   */
  compilers: {
    less: {
      compress: prod
    },
    /*sass: {
      outputStyle: 'compressed'
    },*/
    babel: {
      sourceMap: true,
      presets: [
        'env'
      ],
      /*
       plugins爲1.1.6版本之後的功能
       目前支持js壓縮wepy-plugin-ugliyjs、圖片壓縮wepy-plugin-imagemin
       其他plugin持續開發中
      */
      plugins: [
        'transform-class-properties',
        'transform-decorators-legacy',
        'transform-object-rest-spread',
        'transform-export-extensions',
      ]
    }
  },
  plugins: {},
/*在使用的地方先引入import wepy from 'wepy'; 然後wepy.$appConfig.屬性名。eg:wepy.$appConfig.baseUrl*/
  appConfig: {
    baseUrl:process.env.NODE_ENV === 'production'? 'https://api.a.com/' : 'https://api.a.com/dev/',
    noPromiseAPI: ['createSelectorQuery']
  }
}

if (prod) {

  // 壓縮sass
  module.exports.compilers['less'] = {outputStyle: 'compressed'}

  // 壓縮js
  module.exports.plugins = {
    uglifyjs: {
      filter: /\.js$/,
      config: {}
    },
    imagemin: {
      filter: /\.(jpg|png|jpeg)$/,
      config: {
        jpg: {
          quality: 80
        },
        png: {
          quality: 80
        }
      }
    }
  }
}

相關鏈接:mpvue文檔原生小程序文檔公衆號文檔

博客地址:https://my.oschina.net/wangnian

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章