注冊(cè)登錄

微信小程序組件化開發(fā)框架文檔

2017-05-22
導(dǎo)讀:微信小程序推出之時(shí),限制非常多,現(xiàn)在越來越開放。微信小程序開發(fā)文檔也受到越來越多人的關(guān)注,下面從多個(gè)方面來談?wù)勎⑿判〕绦蜷_發(fā)文檔的一些內(nèi)容。...

  2017年5月22日,微信小程序推出之時(shí),限制非常多,現(xiàn)在越來越開放。微信小程序開發(fā)文檔也受到越來越多人的關(guān)注,下面從多個(gè)方面來談?wù)勎⑿判〕绦蜷_發(fā)文檔的一些內(nèi)容。

小程序框架wepy文檔

成品DEMO展示

微信小程序組件化開發(fā)框架文檔

一個(gè)是使用 wepy new demo 命令生成的標(biāo)準(zhǔn)demo

一個(gè)是基于wepy開發(fā)的手機(jī)充值的完整demo

一個(gè)是基于wepy開發(fā)的開源的仿微信的聊天界面 (源代碼下載)

以上三個(gè)demo均在安卓機(jī)和IOS機(jī)上運(yùn)行過通。

快速入門

代碼規(guī)范:

1 . 變量與方法使用盡量使用駝峰式命名,避免使用 $ 開頭。

$ 開頭的方法或者屬性為框架內(nèi)建方法或者屬性,可以被使用,使用前請(qǐng)參考 API文檔 。

2 .入口,頁(yè)面,組件的命名后綴為 .wpy 。外鏈的文件可以是其它后綴。

請(qǐng)參考 wpy文件說明

3 .使用ES6語法開發(fā)。

框架在ES6下開發(fā),因此也需要使用ES6開發(fā)小程序,ES6中有大量的語法糖可以讓我們的代碼更加簡(jiǎn)潔高效。

4 .使用Promise

框架默認(rèn)對(duì)小程序提供的API全都進(jìn)行了 Promis小程序第三方平臺(tái)e 處理,甚至可以直接使用async/await等新特性進(jìn)行開發(fā)。

項(xiàng)目創(chuàng)建與使用

安裝wepy

以下安裝都通過npm安裝

注:在騰訊開發(fā)網(wǎng),因?yàn)閚pm需要使用代理才可以,沒使用npm代理的同學(xué)建議使用騰訊內(nèi)部工具tnmp代替npm安裝,tnpm的安裝與使用請(qǐng)參考 alsotan g的文章。

1 .安裝 wepy 命令行工具

npm install wepy-cli -g

2 .在開發(fā)目錄生成開發(fā)DEMO

wepy new myproject

3 .開發(fā)實(shí)時(shí)編譯

wepy build --watch

項(xiàng)目目錄結(jié)構(gòu)

dist
node_modules
src
 components
     com_a.wpy
     com_b.wpy
 pages
     index.wpy
     page2.wpy
app.wpy
package.json

開發(fā)使用說明

1 .使用微信開發(fā)者工具新建項(xiàng)目,本地開發(fā)選擇dist目錄。

2 .微信開發(fā)者工具 —> 項(xiàng)目 —> 關(guān)閉ES6轉(zhuǎn)ES5。

3 .本地項(xiàng)目根目錄運(yùn)行wepy build --watch,開啟實(shí)時(shí)編譯。

主要解決問題:

1. 開發(fā)模式轉(zhuǎn)換

在原有的小程序的開發(fā)模式下進(jìn)行再次封裝,更貼近于現(xiàn)有MVVM框架開發(fā)模式??蚣茉陂_發(fā)過程中參考了一些現(xiàn)在框架的一些特性,并且融入其中,以下是使用wep小程序制作y前后的代碼對(duì)比圖。

官方DEMO代碼:

//index.js
//獲取應(yīng)用實(shí)例
var app = getApp()
Page({
  data: {
  motto: 'Hello World',
  userInfo: {}
  },
  //事件處理函數(shù)
  bindViewTap: function() {
  console.log('button clicked')
  },
  onLoad: function () {
  console.log('onLoad')
  }
})

基于wepy的實(shí)現(xiàn):

import wepy from 'wepy';

export default class Index extends wepy.page {

  data = {
  motto: 'Hello World',
  userInfo: {}
  };
  methods = {
  bindViewTap () {
  console.log('button clicked');
  }
  };
  onLoad() {
  console.log('onLoad');
  };
}

2. 支持組件化開發(fā)

參見章節(jié): 組件

示例代碼:

// index.wpy
<template>
  <view>
  <component id="pannel" path="pannel"></component>
  <component id="counter1" path="counter"></component>
  <component id="counter2" path="counter"></component>
  <component id="list" path="list"></component>
  </view>
</template>
<script>
import wepy from 'wepy';
import List from '../components/list';
import Panel from '../components/panel';
import Counter from '../components/counter';

export default class Index extends wepy.page {

  config = {
  "navigationBarTitleText": "test"
  };
  components = {
  panel: Panel,
  counter1: Counter,
  counter2: Counter,
  list: List
  };
}
</script>

3. 支持加載外部NPM包。

在編譯過程當(dāng)中,會(huì)遞歸遍歷代碼中的require然后將對(duì)應(yīng)依賴文件從node_modules當(dāng)中拷貝出來,并且修改require為相對(duì)路徑,從而實(shí)現(xiàn)對(duì)外部NPM包的支持。如下圖:

微信小程序組件化開發(fā)框架文檔

4. 單文件模式,使得目錄結(jié)構(gòu)更加清晰。

官方目錄結(jié)構(gòu) 要求app必須有三個(gè)文件app.json,app.js,app.wxss,頁(yè)面有4個(gè)文件 index.json,index.js,index.wxml,index.wxss。而且文件必須同名。

所以使用wepy開發(fā)前后開發(fā)目錄對(duì)比如下:

官方DEMO:

project
    pages
        index
        index.json
        index.js
        index.wxml
        index.wxss
    log
        log.json
        log.wxml
        log.js
        log.wxss
    app.js
    app.json
    app.wxss

使用wepy框架后目錄結(jié)構(gòu):

project
    src
    pages
        index.wpy
        log.wpy
    app.wpy

默認(rèn)使用babel編譯,支持ES6/7的一些新特性。

用戶可以通過修改wepy.config.js配置文件,配置自己熟悉的babel環(huán)境進(jìn)行開發(fā)。默認(rèn)開啟使用了一些新的特性如promise,async/await等等。

示例代碼:

import wepy from 'wepy';

export default class Index extends wepy.page {

  getData() {
      return new Promise((resolve, reject) => {
          setTimeout(() => {
              resolve({data: 123});
          }, 3000);
      });
  };
  async onLoad() {
      let data = await this.getData();
      console.log(data.data);
  };
}

5. 針對(duì)原生API進(jìn)行優(yōu)化

對(duì)現(xiàn)在API進(jìn)行promise處理,同時(shí)修復(fù)一些現(xiàn)有API的缺陷,比如:wx.request并發(fā)問題等。

原有代碼:

onLoad = function () {
  var self = this;
  wx.login({
      success: function (data) {
          wx.getUserInfo({
              success: function (userinfo) {
                  self.setData({userInfo: userinfo});
              }
      });
  }
  });

}

基于wepy實(shí)現(xiàn)代碼:

async onLoad() {
  await wx.login();
  this.userInfo = await wx.getUserInfo();
}

在同時(shí)并發(fā)10個(gè)request請(qǐng)求測(cè)試時(shí):

不使用wepy:

微信小程序組件化開發(fā)框架文檔

微信小程序組件化開發(fā)框架文檔

使用wepy后:

微信小程序組件化開發(fā)框架文檔

進(jìn)階說明

wepy.config.js 配置文件說明

執(zhí)行wepy new demo后,會(huì)生成類似配置文件。

let prod = process.env.NODE_ENV === 'production';

module.exports = {
  "wpyExt": ".wpy",
  "babel": {
    "presets": [
      "es2015",
      "stage-1"
    ],
    "plugins": [
      "transform-export-extensions",
      "syntax-export-extensions",
      "transform-runtime"
    ]
  }
};


if (prod) {
  // 壓縮sass
  module.exports['sass'] = {"outputStyle": "compressed"};

  // 壓縮less
  module.exports['less'] = {"compress": true};

  // 壓縮js
  module.exports.plugins = {
      'UglifyJsPlugin': {
          filter: /\.js$/,
          config: {
              compress: {
                warning: false
              }
          }
      },
      'TestPlugin': {
          filter: /\.wxml$/,
          config: {
          }
      }
  };
}

wpyExt:缺省值為’.wpy’,IDE默認(rèn)情況下不會(huì)對(duì)此文件類型高亮,此時(shí)可以修改所有文件為.vue后綴(因?yàn)榕cvue高亮規(guī)則一樣),然后將此選項(xiàng)修改為.vue,就能解決部分IDE代碼高亮問題。

sa小程序設(shè)計(jì)ss:sass編譯配置,參見 這里

less:less編譯配置,參見 這里

babel:babel編譯配置,參見 這里

plugins:plugins為1.1.6版本之后功能,目前支持js壓縮與圖片壓縮,持續(xù)開發(fā)……

wpy文件說明

wpy文件的編譯過程過下:

微信小程序組件化開發(fā)框架文檔

一個(gè) .wpy 文件分為三個(gè)部分:

樣式 <style></style> 對(duì)應(yīng)原有wxss

模板 <template></template> 對(duì)應(yīng)原有wxml

代碼 <script></script> 對(duì)應(yīng)原有js

其中入口文件app.wpy不需要template,所以編譯時(shí)會(huì)被忽略。這三個(gè)標(biāo)簽都支持type和src屬性,type決定了其代碼編譯過程,src決定是否外聯(lián)代碼,存在src屬性且有效時(shí),忽略內(nèi)聯(lián)代碼,示例如下:

<style type="less" src="page1.less"></style>
<template type="wxml" src="page1.wxml"></template>
<script>
  // some code
</script>

標(biāo)簽對(duì)應(yīng) type 值如下表所示:

|標(biāo)簽|type默認(rèn)值|type支持值|
|—|—|—|
|style|css|css,less,sass(待完成)|
|template|wxml|wxml,xml,html(待完成)|
|script|js|js,TypeScript(待完成)|

script說明

程序入口app.wpy

<style type="less">
/** less **/
</style>
<script>
import wepy from 'wepy';
export default class extends wepy.app {
  config = {
      "pages":[
      "pages/index/index"
  ],
  "window":{
      "backgroundTextStyle": "light",
      "navigationBarBackgroundColor": "#fff",
      "navigationBarTitleText": "WeChat",
      "navigationBarTextStyle": "black"
  }
  };
  onLaunch() {
      console.log(this);
  }
}
</script>

入口app.wpy繼承自wepy.app,包含一個(gè)config屬性和其全局屬性、方法、事件。其中config屬性對(duì)應(yīng)原有的app.json,編譯時(shí)會(huì)根據(jù)config生成app.json文件,如果需要修改config中的內(nèi)容,請(qǐng)使用系統(tǒng)提供API。

頁(yè)面index.wpy

<style type="less">
/** less **/
</style>
<template type="wxml">
  <view>
  </view>
  <component id="counter1" path="counter"></component>
</template>
<script>
import wepy form 'wepy';
import Counter from '../components/counter';
export default class Index extends wepy.page {

  config = {};
  components = {counter1: Counter};

  data = {};
  methods = {};

  events = {};
  onLoad() {};
  // Other properties
}
</script>

頁(yè)面入口繼承自wepy.page,主要屬性說明如下:

微信小程序組件化開發(fā)框架文檔

組件com.wpy

<style type="less">
/** less **/
</style>
<template type="wxml">
  <view> </view>
</template>
<script>
import wepy form 'wepy';
export default class Com extends wepy.component {

  components = {};

  data = {};
  methods = {};

  events = {};
  // Other properties
}
</script>

頁(yè)面入口繼承自wepy.component,屬性與頁(yè)面屬性一樣,除了不需要config以及頁(yè)面特有的一些小程序事件等等。

組件

在小程序中,可以利用 JS模塊化 和 wxml模板 ,對(duì)業(yè)務(wù)模塊進(jìn)行劃分,實(shí)現(xiàn)如下效果:

微信小程序組件化開發(fā)框架文檔

但實(shí)際上不同的模塊代碼與事件交互都是在同一個(gè)頁(yè)面空間處理的,比如說 moduleA 和 moduleB 中同時(shí)存在一個(gè) add 響應(yīng)事件時(shí),就需要在 html 和 js 中分別定義為 moduleA_add,moduleB_add。業(yè)務(wù)模塊復(fù)雜之后就不利于開發(fā)和維護(hù)。

在wepy中,利用組件化的特性可以解決此類問題,如下圖:

微信小程序組件化開發(fā)框架文檔

ComA 和 ComB中間的數(shù)據(jù)與事件相互隔離,可以分別擁有自己的add事件。

組件引用

當(dāng)頁(yè)面或者組件需要引入子組件時(shí),需要在頁(yè)面或者script中的components給組件分配唯一id,并且在template中添加 <component> 標(biāo)簽,如index.wpy

Index頁(yè)面引入A,B,C三個(gè)組件,同時(shí)組件A和B又有自己的子組件D,E,F(xiàn),G,H。

組件通信與交互

wepy.component基類提供三個(gè)方法$broadcast,$emit,$invoke,因此任一頁(yè)面或任一組件都可以調(diào)用上述三種方法實(shí)現(xiàn)通信與交互,如:

$this.$emit('some-event', 1, 2, 3, 4);

組件的事件監(jiān)聽需要寫在events屬性下,如:

import wepy form 'wepy';
export default class Com extends wepy.component {

  components = {};

  data = {};
  methods = {};

  events = {
      'some-event': ($event, ...args) {
          console.log(`${this.name} receive ${$event.name} from ${$event.source.name}`);
      }
  };
  // Other properties
}

1 . $broadcast

$broadcast事件是由父組件發(fā)起,所有子組件都會(huì)收到此廣播事件,除非事件被手動(dòng)取消。事件廣播的順序?yàn)閺V度優(yōu)先搜索順序,如果Page_Index發(fā)起一個(gè)$broadcast事件,那么接收到事件的先后順序?yàn)椋篈, B, C, D, E, F, G, H。如下圖:

微信小程序組件化開發(fā)框架文檔

2 .$emit

$emit與$broadcast正好相反,事件發(fā)起組件的父組件會(huì)依次接收到$emit事件,如上圖,如果E發(fā)起一個(gè)$emit事件,那么接收到事件的先后順序?yàn)椋篈, Page_Index。如下圖:

微信小程序組件化開發(fā)框架文檔

3 .$invoke

$i微信小程序 apinvoke是一個(gè)組件對(duì)另一個(gè)組件的直接調(diào)用,通過傳入的組件路徑找到相應(yīng)組件,然后再調(diào)用其方法。

如果想在Page_Index中調(diào)用組件A的某個(gè)方法:

this.$invoke('ComA', 'someMethod', 'someArgs');

如果想在組件A中調(diào)用組件G的某個(gè)方法:

this.$invoke('./../ComB/ComG', 'someMethod', 'someArgs');

混合

混合可以將組之間的可復(fù)用部分抽離,從而在組件中使用混合時(shí),可以將混合的數(shù)據(jù),事件以及方法注入到組件之中?;旌戏址譃閮煞N:

  • 默認(rèn)式混合

  • 兼容式混合

默認(rèn)式混合

對(duì)于組件data數(shù)據(jù),components組件,events事件以及其它自定義方法采用 默認(rèn)式混合 ,即如果組件未聲明該數(shù)據(jù),組件,事件,自定義方法等,那么將混合對(duì)象中的選項(xiàng)將注入組件這中。對(duì)于組件已聲明的選項(xiàng)將不受影響。

// mixins/test.js
import wepy from 'wepy';

export default class TestMixin extends wepy.page {
    data = {
        foo: 'foo defined by page',
        bar: 'bar defined by testMix'
    };
    methods: {
        tap () {
            console.log('mix tap');
        }
    }
}

// pages/index.wpy
import wepy from 'wepy';
import TestMixin from './mixins/test';

export default class Index extends wepy.mixin {
    data = {
        foo: 'foo defined by index'
    };
    mixins = [TestMixin ];
    onShow() {
        console.log(this.foo); // foo defined by index.
        console.log(this.bar); // foo defined by testMix.
    }
}

兼容式混合

對(duì)于組件methods響應(yīng)事件,以及小程序頁(yè)面事件將采用兼容式混合,即先響應(yīng)組件本身響應(yīng)事件,然后再響應(yīng)混合對(duì)象中響應(yīng)事件。

// mixins/test.js
import wepy from 'wepy';

export default class TestMixin extends wepy.page {
    methods = {
        tap () {
            console.log('mix tap');
        }
    };
    onShow() {
        console.log('mix onshow');
    }
}

// pages/index.wpy
import wepy from 'wepy';
import TestMixin from './mixins/test';

export default class Index extends wepy.mixin {

    mixins = [TestMixin];
    methods = {
        tap () {
            console.log('index tap');
        }
    };
    onShow() {
        console.log('index onshow');
    }
}


// index onshow
// mix onshow
// ----- when tap
// index tap
// mix tap

數(shù)據(jù)綁定

小程序數(shù)據(jù)綁定方式

小程序通過Page提供的setData方法去綁定數(shù)據(jù),如:

this.setData({title: 'this is title'});

因?yàn)樾〕绦蚣軜?gòu)本身原因,頁(yè)面渲染層和JS邏輯層分開的,setData操作實(shí)際就是JS邏輯層與頁(yè)面渲染層之間的通信,那么如果在同一次運(yùn)行周期內(nèi)多次執(zhí)行setData操作時(shí),那么通信的次數(shù)是一次還是多次呢?經(jīng)過跟小程序團(tuán)隊(duì)確認(rèn)后得知多次setData會(huì)執(zhí)行多次通信。

wepy數(shù)據(jù)綁定方式

wepy使用臟數(shù)據(jù)檢查對(duì)setData進(jìn)行封裝,在函數(shù)運(yùn)行周期結(jié)束時(shí)執(zhí)行臟數(shù)據(jù)檢查,一來可以不用關(guān)心頁(yè)面多次setData是否會(huì)有性能上的問題,二來可以更加簡(jiǎn)潔去修改數(shù)據(jù)實(shí)現(xiàn)綁定,不用重復(fù)去寫setData方法。代碼如下:

this.title = 'this is title';

但需注意,在函數(shù)運(yùn)行周期之外的函數(shù)里去修改數(shù)據(jù)需要手動(dòng)調(diào)用$apply方法。如:

setTimeout(() => {
  this.title = 'this is title';
  this.$apply();
}, 3000);

wepy臟數(shù)據(jù)檢查流程

在執(zhí)行臟數(shù)據(jù)檢查是,會(huì)通過this.$$phase標(biāo)識(shí)當(dāng)前檢查狀態(tài),并且會(huì)保證在并發(fā)的流程當(dāng)中,只會(huì)有一個(gè)臟數(shù)據(jù)檢查流程在運(yùn)行,以下是執(zhí)行臟數(shù)據(jù)檢查的流程圖:

微信小程序組件化開發(fā)框架文檔

其它優(yōu)化細(xì)節(jié)

1. wx.request 接收參數(shù)修改

點(diǎn)這里查看 官方文檔

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

// wepy 使用方式
// request 接口從只接收Object變?yōu)榭山邮誗tring
wx.request('xxxx').then((d) => console.log(d));

2. 優(yōu)化事件參數(shù)傳遞

點(diǎn)這里查看 官方文檔

// 官方
<view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view>
Page({
  tapName: function(event) {
    console.log(event.currentTarget.hi)// output: WeChat
  }
});

// wepy 建議傳參方式
<view id="tapTest" data-wepy-params="1-wepy-something" bindtap="tapName"> Click me! </view>

events: {
    tapName (event, id, title, other) {
        console.log(id, title, other)// output: 1, wepy, something
    }
}

3. 改變數(shù)據(jù)綁定方式

保留setData方法,但不建議使用setData執(zhí)行綁定,修復(fù)傳入undefined的bug,并且修改入?yún)⒅С郑?/p>

  • this.setData(target, value)

  • this.setData(object)

點(diǎn)這里查看 官方文檔

// 官方
<view> {{ message }} </view>

onLoad: function () {
    this.setData({message: 'hello world'});
}


// wepy
<view> {{ message }} </view>

onLoad () {
    this.message = 'hello world';
}

4. 組件代替模板和模塊

點(diǎn)這里查看 官方文檔

// 官方
<!-- 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>
    <component id="item"></component>
</template>
<script>
    import wepy from 'wepy';
    import Item from '../componen制作小程序ts/item';
    export default class Index extends wepy.page {
        components = { Item }
    }
</script>

API

wepy.event

微信小程序組件化開發(fā)框架文檔

wepy.component

微信小程序組件化開發(fā)框架文檔

微信小程序組件化開發(fā)框架文檔

wepy.page

微信小程序組件化開發(fā)框架文檔

wepy.app

微信小程序組件化開發(fā)框架文檔

CHANGELOG

1.3.1 (2016-12-16)

  • 新增對(duì)第三方Compiler的支持

  • 新增pug編譯器

  • 重新整理代碼結(jié)構(gòu),使用lerna維護(hù)不同的NPM包

  • 重新處理Plugins,同樣交由第三方包處理

  • 添加了編譯時(shí)檢測(cè)依賴的Compiler或者Plugins是否缺失的邏輯,如果缺失會(huì)自行安裝

  • 如何制作小程序
  • 添加了cli工具版本檢測(cè)的功能

1.1.9 (2016-12-14)

  • 新增了wepy upgrade命令升級(jí)wepyjs版本

  • 新增對(duì)第三方組件的支持

  • 新增第三方組件[wepy-com-toast]

  • 模板中添加toast組件測(cè)試

1.1.8 (2016-12-08)

  • 修復(fù)了script使用src外鏈報(bào)錯(cuò)的BUG

  • 修復(fù)了LESS編譯會(huì)調(diào)用到SASS的BUG

  • 優(yōu)化了事件傳參數(shù),支持直接傳參

  • 加入了Travis-CI以及Coveralls

  • 修復(fù)其它細(xì)節(jié)BUG問題

1.1.7 (2016-12-06)

  • script/template/style的屬性同時(shí)支持type和lang

  • 添加mixins支持

1.1.6 (2016-12-02)

  • 修復(fù)了組件ID大寫導(dǎo)致無法識(shí)別的問題

  • 添加了對(duì)小程序頁(yè)面所有響應(yīng)事件的支持

  • 修改wepy.config.js支持plugins

  • 添加UglifyJsPlugin,在編譯時(shí)對(duì)生成的所有JS文件進(jìn)行壓縮

  • 添加ImageMinPlugin(不推薦使用,處理大圖片時(shí)還有問題)

  • 添加wepy build --no-cache參數(shù),編譯時(shí)會(huì)重新編譯所有依賴文件

  • wepy new demo時(shí),由在當(dāng)前目錄下生成項(xiàng)目改為創(chuàng)建demo目錄,然后再生成項(xiàng)目

  • 更新生成demo支持最新功能

1.1.4 (2016-12-01)

  • 添加了小程序其它頁(yè)面事件的支持

  • 修改默認(rèn)配置文件.wepyrc為wepy.config.js,方便以后功能擴(kuò)展。(兼容老配置文件

1.1.3 (2016-11-28)

  • 修復(fù)SASS編譯異常導(dǎo)致watch結(jié)束的BUG

  • 修復(fù)子組件修改時(shí)不會(huì)觸發(fā)父組件更新的BUG

  • 修復(fù)$invoke('../')的BUG

  • 修復(fù)頁(yè)面onLoad事件中傳參的BUG

1.1.1 (2016-11-23)

  • 添加了對(duì)sass/scss的編譯支持

  • .wepyrc中加入對(duì)less/sass的配置支持

  • .wepyrc中添加wpyExt選項(xiàng)

  • 更新生成模板

  hishop微信小程序可以實(shí)現(xiàn)一鍵開通微信小程序,結(jié)合移動(dòng)云商城,可以實(shí)現(xiàn)七大端口的線上和線下結(jié)合模式。

重磅推薦:小程序開店目錄

第一部分:小商店是什么

第二部分:如何開通一個(gè)小商店

第三部分:如何登錄小商店

第四部分:開店任務(wù)常見問題

第五部分:小商店可以賣什么

第六部分:HiShop小程序特色功能

第七部分:小程序直播

第八部分:小程序收貨/物流

第九部分:小程序怎么結(jié)算

第十部分:小程序客服

第十一部分:電商創(chuàng)業(yè)

第十二部分:小程序游戲開發(fā)

電話咨詢 微信咨詢 預(yù)約演示 0元開店