午夜91福利视频,午夜成人在线观看,午夜在线视频免费观看,午夜福利短视频,精品午夜成人免费视频APP

小程序模板網

簡易商城小程序全棧開發(mpvue+koa+mongodb)

發布時間(jian):2018-07-27 11:52 所屬欄目:小程序開發教程

接觸小(xiao)程序(xu)有一段時間后(hou)并且多(duo)多(duo)少少做了一些項目之(zhi)后(hou),又開(kai)(kai)始了vue的(de)旅(lv)程,受其核心思想的(de)影響(xiang),對數據/狀(zhuang)態管理、組(zu)件化(hua)、跨平臺等都有較高(gao)的(de)追求,mpvue 是(shi)一個(ge)使用 Vue.js開(kai)(kai)發小(xiao)程序(xu)的(de)前端框架,由此開(kai)(kai)始了mpvue踩(cai)坑之(zhi)旅(lv),想在提高(gao)代碼(ma)可讀性的(de)同時,也增加一點vue.js的(de)開(kai)(kai)發體(ti)驗。

技術棧

前端(duan): 微信(xin)小程(cheng)序(xu)、mpvue

后端:koa

數(shu)據庫:mongodb 數(shu)據庫可視化工具:Robo3T

商城小程序開跑

一(yi)個基(ji)本的(de)商城小程(cheng)序(xu),包含(han)了(le)前端的(de)首頁(ye)、分(fen)類、購物車、我(wo)的(de)(訂(ding)單)四個tab頁(ye),后端的(de)數(shu)據(ju)定義、分(fen)類、和(he)存(cun)取。各有(you)(you)其色,我(wo)在下面就相應(ying)介紹一(yi)些主要功能、對(dui)比原生小程(cheng)序(xu)和(he)vue.js所踩到的(de)坑還(huan)有(you)(you)后端數(shu)據(ju)庫(ku)的(de)功能應(ying)用。 想了(le)解或者有(you)(you)何問題(ti)都可(ke)以去 作(zuo)品源(yuan)碼 中了(le)解哦。

成果分享

一、前臺頁面及功能展示

首(shou)頁:


加入購物車:

購(gou)物車全選結算:

地址管理:

1. 談組件封裝

舉個栗(li)子說(shuo),首頁(ye)由三部分組成:頭(tou)部輪播(bo)推薦(jian)+中(zhong)(zhong)間橫向(xiang)滑動(dong)(dong)推薦(jian)+縱向(xiang)滾動(dong)(dong)商(shang)品list。這三部分,幾乎是(shi)所有(you)商(shang)城類app必需(xu)的功(gong)能了。頭(tou)部的輪播(bo)推薦(jian)、中(zhong)(zhong)間的橫向(xiang)滑動(dong)(dong)式(shi)推薦(jian)的封裝(zhuang),我(wo)們(men)都(dou)知道(dao),諸如(ru)此類的功(gong)能組件(jian),在各app上基本都(dou)少(shao)(shao)不(bu)(bu)了,最(zui)初學vue最(zui)先有(you)所體會的,便是(shi)組件(jian)代(dai)碼(ma)復用(yong)性高的特點(dian),在進行(xing)一些組件(jian)復用(yong)遷移至別的組件(jian)或(huo)(huo)頁(ye)面時,可能都(dou)不(bu)(bu)需(xu)要改動(dong)(dong)代(dai)碼(ma)或(huo)(huo)者(zhe)改動(dong)(dong)少(shao)(shao)量(liang)代(dai)碼(ma)就(jiu)可以直接(jie)使用(yong),可以說(shuo)是(shi)相當方便了,對于mpvue組件(jian)內仍然支持(chi)原生小(xiao)(xiao)程序(xu)(xu)的swiper與scroll,兩者(zhe)兼容(rong)后,對于熟知小(xiao)(xiao)程序(xu)(xu)和vue的開發(fa)者(zhe),這項功(gong)能可以很(hen)高效率地完成。

最后主(zhu)頁面文件就是(shi)由(you)一個(ge)個(ge)組件組成,可讀性很強(qiang)了,對于(yu)初學者來說,模塊封裝的思想是(shi)首先就得具備(bei)的了。

<template>
  <div class="container" @click="clickHandle('test click', $event)">
    <div class="swiperList">
      <swiper :text="motto" :swiperList="swiperlist"></swiper>
    </div>
    <div class="navTab">
      <div class="recTab">
        <text>  ——  為你推薦  ——</text>
    </div>
    </div>
    <scroll></scroll>
    <div class="hot">
      <span> —— 熱門商品 ——</span>
    </div>
    <hot :v-text="motto"></hot>
    <div class="fixed-img">
      <img :src="fixImg" alt="" class="fix-img">
    </div>
  </div>
</template>
復制代碼

不過關于組件封裝與組合的(de)問(wen)(wen)題,由于最(zui)近有研究vue性(xing)能優(you)化和用戶體驗的(de)一(yi)些知識點(dian),考慮了一(yi)個(ge)比(bi)較嚴肅(su)的(de)問(wen)(wen)題:

先看一下(xia)常見的(de)vue寫(xie)法:在html里放一個app組件(jian)(jian),app組件(jian)(jian)里又引用了(le)其(qi)他(ta)的(de)子組件(jian)(jian),形成一棵以app為(wei)根節點的(de)組件(jian)(jian)樹(shu):

<body>
    <app></app> 
</body>
復制代碼

而這(zhe)種(zhong)做法(fa)就引發了性能問題,要初(chu)始(shi)(shi)(shi)化一個父組(zu)件(jian),必然需要先初(chu)始(shi)(shi)(shi)化它的子組(zu)件(jian),而子組(zu)件(jian)又有(you)它自己的子組(zu)件(jian)。那么(me)要初(chu)始(shi)(shi)(shi)化根標簽,就需要從底層開始(shi)(shi)(shi)冒泡,將頁面所(suo)有(you)組(zu)件(jian)都初(chu)始(shi)(shi)(shi)化完。所(suo)以我們(men)的頁面會在所(suo)有(you)組(zu)件(jian)都初(chu)始(shi)(shi)(shi)化完才開始(shi)(shi)(shi)顯示。

這個(ge)結果顯然(ran)不是(shi)我們(men)要(yao)的,用戶每(mei)次點開(kai)頁面(mian),還要(yao)面(mian)對一陣子的空白和(he)響應(ying),因為頁面(mian)啟動后不止要(yao)響應(ying)初(chu)始化頁面(mian)的組件,還有包含在app里的其他組件,這樣嚴(yan)重拖(tuo)慢了頁面(mian)打開(kai)的速度(du)。

更好(hao)的結果是頁面可以從上到(dao)下(xia)按順序(xu)流式渲染(ran),這(zhe)樣可能總體時間增長了(le),但首屏時間縮(suo)減,在(zai)用戶看(kan)來,頁面打開速度就更快(kuai)了(le)。網上一(yi)些辦法大同小異,各有(you)優缺點,所以...本(ben)人也在(zai)瘋(feng)狂(kuang)試驗中,靜待好(hao)消息。

**2.Class、Style的綁定 **

在(zai)(zai)不(bu)同(tong)父(fu)組件中引用同(tong)一子組件時,但是各(ge)自需要接(jie)收綁定的動態樣(yang)式(shi)(shi)去呈現不(bu)同(tong)的樣(yang)式(shi)(shi),在(zai)(zai)綁定css style樣(yang)式(shi)(shi)這一關上,踩了(le)個大坑:mpvue居然(ran)不(bu)支持(chi)用object的形(xing)式(shi)(shi)傳style,起先處于樣(yang)式(shi)(shi)一直上不(bu)去的抓(zhua)狂當中,網上對于mpvue這方面的細(xi)節也少之又少,后來查找了(le)許多地方,發現class和(he)style的綁定都(dou)是不(bu)支持(chi)classObj和(he)styleObj形(xing)式(shi)(shi),就(jiu)嘗(chang)試(shi)用了(le)字符串,果然(ran)...改代(dai)碼(ma)改到懷疑人生(sheng),結果你告訴我人生(sheng)起步就(jiu)是錯(cuo)誤,怎能不(bu)心痛?...

解(jie)決:

<template>
<div class="swiper-list">
    <d-swiper :swiperList="swiperlist" :styleObject="styleobject"></d-swiper>
</div>
</template>
<script>
    data() {
        return {
            styleobject:'width:100%;height:750rpx;position:absolute;top:0;z-index:3'
        }
    }
</script>
復制代碼

3. “v-for嵌套”陷阱

在做(zuo)vue項目的時(shi)候難免會用(yong)(yong)到(dao)(dao)循環(huan)(huan),需要用(yong)(yong)到(dao)(dao)index索引值,但是v-for在嵌(qian)套時(shi)index沒辦法重復用(yong)(yong),內循環(huan)(huan)與外循環(huan)(huan)不能共用(yong)(yong)一個index。

<swiper-item v-for="(items,index) in swiperList" :key="index">
    <div v-for="item in items" class="swiper-info" :key="item.id" @click="choose" >
        <image :src="item.url"  class="swiper-image" :style="styleObject"/>
    </div>
</swiper-item>
復制代碼

以上(shang)代(dai)碼就會報錯:

而給內(nei)循環再加上(shang)另一(yi)個索引(yin),便沒有(you)報(bao)錯:

<swiper-item v-for="(items,index) in swiperList" :key="index">
    <div v-for="(item,i) in items" class="swiper-info" :key="i" @click="choose" >
        <image :src="item.url"  class="swiper-image" :style="styleObject"/>
    </div>
</swiper-item>
復制代碼

4.this指向問題與箭頭函數的應用

這是vue文檔里的原話:All lifecycle hooks are called with their 'this' context pointing to the Vue instance invoking it.

意思是(shi):在Vue所有的(de)生命周期鉤(gou)子方法(fa)(如created,mounted, updated以(yi)及destroyed)里使用this,this指向(xiang)調用它的(de)Vue實例,即(new Vue)。 mpvue里同理。 我(wo)們(men)都知道,生命周期函數中的(de)this都是(shi)指向(xiang)Vue實例的(de),因此我(wo)們(men)就可以(yi)訪問數據,對屬性和方法(fa)進(jin)行運算。

props:{
    goods:Array
},
mounted: function(options){
    let category = [
      {id: 0, name: '全部'},
      {id: 1, name: 'JAVA'},
      {id: 2, name: 'C++'},
      {id: 3, name: 'PHP'},
      {id: 4, name: 'VUE'},
      {id: 5, name: 'CSS'},
      {id: 6, name: 'HTML'},
      {id: 7, name: 'JavaScript'}
    ]
    this.categories = category
    this.getGoodsList(0)
  },
methods: {
    getGoodsList(categoryId){
      console.log(categoryId);
      if(categoryId == 0){
        categoryId = ''
      }
      wx.request({
        url: '//localhost:3030/shop/goods/list',
        data: {
          categoryId: categoryId
        },
        method: 'POST', 
        success: res => {
          console.log(res);
          this.goods = res.data.data;
        }
      })
    },
}
復制代碼

普通函(han)數(shu)(shu)this指向(xiang)這個函(han)數(shu)(shu)運行的(de)(de)(de)上下文(wen)環(huan)境(jing),也就是調(diao)用(yong)(yong)它(ta)的(de)(de)(de)上下文(wen),所(suo)(suo)以在這里,對于生命周期函(han)數(shu)(shu)用(yong)(yong)普通函(han)數(shu)(shu)還是箭頭函(han)數(shu)(shu)其實并沒(mei)(mei)有影(ying)響,因為它(ta)的(de)(de)(de)定義(yi)環(huan)境(jing)與運行環(huan)境(jing)是同一個,所(suo)(suo)以同樣能取到vue實例中(zhong)(zhong)數(shu)(shu)據、屬(shu)性和(he)方法(fa)。 箭頭函(han)數(shu)(shu)中(zhong)(zhong),this指向(xiang)的(de)(de)(de)是定義(yi)它(ta)的(de)(de)(de)最外層代碼塊,()=>{} 等價于 function(){}.bind(this);所(suo)(suo)以this當然(ran)指向(xiang)的(de)(de)(de)是vue實例。起初并沒(mei)(mei)有考(kao)慮到this指向(xiang)的(de)(de)(de)問題,在wx.request({})中(zhong)(zhong)success用(yong)(yong)了(le)普通函(han)數(shu)(shu),結果一直報錯“goods is not defined”,用(yong)(yong)了(le)箭頭函(han)數(shu)(shu)才解決,起初普通函(han)數(shu)(shu)的(de)(de)(de)this指向(xiang) getGoodsList()的(de)(de)(de)上下文(wen)環(huan)境(jing),所(suo)(suo)以一直沒(mei)(mei)辦法(fa)取到值。

5.onLoad與onShow

在(zai)進行首頁點擊商品跳(tiao)轉到詳情(qing)頁時,onLoad()無法獲(huo)取更新數據。

首先(xian)雖然(ran)onLoad: function (options) 這個是(shi)可以接受到值(zhi)的,但是(shi)這個只是(shi)加載(zai)一次,不是(shi)我想要的效果,我需要在(zai)(zai)本頁面(mian)(不關閉的情況下)到另外一個頁面(mian)在(zai)(zai)跳轉(zhuan)進來,接收到對應商(shang)品的數據。

所以需要將(jiang)代(dai)碼放在(zai)onshow內部, 在(zai)每次頁面(mian)加載的(de)時候都(dou)會進行當前(qian)狀態的(de)查詢,查詢對應(ying)數據(ju)的(de)子(zi)對象(xiang),更新渲染到詳情頁上。

onShow: function(options){
    // console.log(this.styleobject)
      // console.log(options)
    wx.getStorage({
      key: 'shopCarInfo',
      success: (res) =>{
        // success
        console.log(`initshopCarInfo:${res.data}`)
        this.shopCarInfo = res.data;
        this.shopNum = res.data.shopNum
      }
    })
    wx.request({
      url: '//localhost:3030/shop/goods/detail',//請求detail數據表的數據
      method: 'POST',
      data: {
        id: options.id
      },
      success: res =>{
        // console.log(res);
        const dataInfo = res.data.data.basicInfo;
        this.saveShopCar = dataInfo;
        this.goodsDetail.name = dataInfo.name;
        this.goodsDetail.minPrice = dataInfo.minPrice;
        this.goodsDetail.goodsDescribe = dataInfo.characteristic;

        let goodsLabel = this.goodsLabel
        goodsLabel = res.data.data;
        // console.log(goodsLabel);
        this.selectSizePrice = dataInfo.minPrice;
        this.goodsLabel.pic = dataInfo.pic;
        this.goodsLabel.name = dataInfo.name;
        this.buyNumMax = dataInfo.stores;
        this.buyNumMin = (dataInfo.stores > 0) ? 1 : 0;
      }
    })
  }
復制代碼

了(le)解小程序(xu)onLoad與onShow生命周期函(han)數(shu):

onLoad:生命周期函數–監聽(ting)小程序初始(shi)化(hua),當小程序初始(shi)化(hua)完成(cheng)時,會觸發 onLoadh(全局只觸發一次(ci))。

onShow:生命周期函數–監聽(ting)小程(cheng)序(xu)顯(xian)示,當小程(cheng)序(xu)啟動,或從后臺進入前臺顯(xian)示,會觸發 onShow。

二、后臺數據庫及數據存取

1.架設 HTTP 服務

在(zai)全局配置文件中: 1).引入koa并實例化

const Koa = require('koa');
const app = new Koa()
復制代碼

2).app.listen(端口號):創建并(bing)返(fan)回 HTTP 服務器,將給定的參數(shu)傳遞給Server#listen()。

const Koa = require('koa');//引入koa框架
const app = new Koa();
app.listen(3000);
這里的app.listen()方法只是以下方法的語法糖:

const http = require('http');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);
復制代碼

這樣基(ji)本的配(pei)置(zhi)完畢,我(wo)們就可以用&ldquo;//localhost3030+請求地址參(can)數”獲取到數據庫(ku)的值(zhi)了。

2.Koa-router路由中間件

koa-router 是常用的 koa 的路由庫(ku)。

如果依靠(kao)ctx.request.url去手動處(chu)理路由(you)(you),將會寫很多(duo)處(chu)理代碼,這(zhe)時候(hou)就需要對(dui)應的路由(you)(you)的中間件(jian)對(dui)路由(you)(you)進行控制(zhi),這(zhe)里介(jie)紹(shao)一(yi)個比(bi)較(jiao)好用的路由(you)(you)中間件(jian)koa-router。

以路由切(qie)換催動界面切(qie)換,”數(shu)據化”界面。

3.建立對象模型

 在構(gou)建函數庫之前(qian),先來聊(liao)聊(liao)對(dui)象的建模(mo)。

Mongoose是在node.js異步環(huan)境下對mongodb進行便(bian)捷操(cao)作(zuo)的對象模(mo)型工具。該npm包封裝了操(cao)作(zuo)mongodb的方法(fa)。

Mongoose有兩個特(te)點(dian):

 1、通(tong)過關(guan)系(xi)型數據庫的思(si)想來設計非關(guan)系(xi)型數

2、基于mongodb驅動,簡(jian)化操(cao)作(zuo)

const mongoose = require('mongoose')

const db = mongoose.createConnection('mongodb://localhost/shop') //建立與shop數據庫的連接(shop是我本地數據庫名)
復制代碼

本地(di)數據(ju)庫shop中建了分別“地(di)址管理”、“商(shang)品詳情”、“訂(ding)單詳情”、“商(shang)品列表”、“用(yong)戶列表&rdquo;五個數據(ju)表:

Schema界面定義數據模型(xing):

Schema用于定義(yi)數據(ju)庫的(de)(de)(de)結構(gou)。類似創建(jian)表(biao)時的(de)(de)(de)數據(ju)定義(yi)(不(bu)僅僅可(ke)(ke)以(yi)定義(yi)文(wen)檔的(de)(de)(de)結構(gou)和屬性,還可(ke)(ke)以(yi)定義(yi)文(wen)檔的(de)(de)(de)實例方法(fa)、靜態模(mo)型方法(fa)、復合(he)索(suo)引(yin)等),每(mei)個Schema會映射到mongodb中的(de)(de)(de)一個collection,但是Schema不(bu)具備操作數據(ju)庫的(de)(de)(de)能力。

數(shu)據(ju)表(biao)跟對象(xiang)的映射(she),同(tong)時(shi)具(ju)有檢查(cha)效果,檢查(cha)每組(zu)數(shu)據(ju)是否滿足模型中定義(yi)的條件 同(tong)時(shi),每個對象(xiang)映射(she)成一個數(shu)據(ju)報(bao)表(biao),就可用該對象(xiang)進行保存操(cao)作,等(deng)同(tong)操(cao)作數(shu)據(ju)表(biao),而非mysql命令(ling)行般(ban)繁瑣的操(cao)作

以“商品(pin)列表”數據表為例:

// 模型通過Schema界面定義。
var Schema = mongoose.Schema;

const listSchema = new Schema({
  barCode: String,
  categoryId: Number,
  characteristic: String,
  commission: Number,
  commissionType: Number,
  dateAdd: String,
  dateStart: String,
  id: Schema.Types.ObjectId,
  logisticsId: Number,
  minPrice: Number,
  minScore: Number,
  name: String,
  numberFav: Number,
  numberGoodReputation: Number,
  numberOrders: Number,
  originalPrice: Number,
  paixu: Number,
  pic: String,
  pingtuan: Boolean,
  pingtuanPrice: Number,
  propertyIds: String,
  recommendStatus: Number,
  recommendStatusStr: String,
  shopId: Number,
  status: Number,
  statusStr: String,
  stores: Number,
  userId: Number,
  videoId: String,
  views: Number,
  weight: Number,
})

復制代碼

定義了數(shu)據(ju)(ju)(ju)表(biao)中需要的(de)數(shu)據(ju)(ju)(ju)項(xiang)的(de)類型,數(shu)據(ju)(ju)(ju)表(biao)傳入數(shu)據(ju)(ju)(ju)后(hou)會一(yi)一(yi)對(dui)應:

4.koa-router“路由庫”

const Router = require('koa-router')()//引入koa-router
const router = new Router();// 創建 router 實例對象
//注冊路由
router.post('/shop/goods/list', async (ctx, next) => {
  const params = ctx.request.body
  //以‘listSchema’的模型去取到Goods的數據
  const Goods = db.db.model('Goods', db.listSchema) //第一個‘db’是require來的自定義的,第二個‘db’是取到連接到mongodb的數據庫,model代指實體數據(根據schema獲取該字段下的數據,然后傳給Goods))
  ctx.body = await new Promise((resolve, reject) => {//ctx.body是ctx.response.body的縮寫,代指響應數據
    //異步,等到獲取到數據之后再將body發出去
    if (params.categoryId) {
      Goods.find({categoryId: params.categoryId},(err, docs) => {
        if (err) {
          reject(err)
        }
        resolve({
          code: 0,
          errMsg: 'success',
          data: docs
        })
      })
    } else {
      Goods.find((err, docs) => {
        if (err) {
          reject(err)
        }
        resolve({
          code: 0,
          errMsg: 'success',
          data: docs
        })
      })
    }
  })
})
復制代碼

所有的數(shu)據庫(ku)操作都(dou)是(shi)異步的操作,所以需(xu)要封裝promise來(lai)實現,由此通(tong)過(guo)(guo)POST “//localhost3030/shop/goods/list”便可(ke)訪(fang)問(wen)本(ben)地shop數(shu)據庫(ku)了(le)。 這里(li)順便提一(yi)下“ctx”的使用(yong),ctx(context)上下文,我們(men)(men)都(dou)知(zhi)道有node.js 中有request(請(qing)求)對象和(he)respones(響應)對象。Koa把這兩(liang)個對象封裝在(zai)ctx對象中。 參數(shu)ctx是(shi)由koa傳入的封裝了(le)request和(he)response的變(bian)量,我們(men)(men)可(ke)以通(tong)過(guo)(guo)它(ta)訪(fang)問(wen)request和(he)response (前(qian)端通(tong)過(guo)(guo)ajax請(qing)求http獲(huo)取(qu)數(shu)據) 我們(men)(men)可(ke)以通(tong)過(guo)(guo)ctx請(qing)求or獲(huo)取(qu)數(shu)據庫(ku)中的數(shu)據。

Ctx.body 屬性就(jiu)是發送(song)給用(yong)戶的內容

body是http協(xie)議(yi)中的響(xiang)應體,header是指響(xiang)應頭

ctx.body = ctx.res.body = ctx.response.body

5.數據緩存之模型層設置

1).為什么要做(zuo)數據緩存?

在(zai)這(zhe)里不得不提(ti)(ti)一(yi)句數據(ju)緩存的(de)(de)重要(yao)性,雖然我(wo)是(shi)從本地數據(ju)庫獲(huo)取的(de)(de)數據(ju),但是(shi)由于需(xu)要(yao)的(de)(de)數據(ju)量較多,再者前面說的(de)(de)性能(neng)(neng)優化還(huan)未(wei)完成,每次(ci)還(huan)是(shi)有一(yi)定(ding)的(de)(de)請求時間,沒必要(yao)每次(ci)打開都去請求一(yi)遍后端,渲染頁(ye)面較慢,所(suo)以需(xu)要(yao)將需(xu)要(yao)經常用到的(de)(de)數據(ju)做本地緩存,這(zhe)樣能(neng)(neng)大大提(ti)(ti)高頁(ye)面渲染速(su)度。

2).設置模(mo)型層

setGoodsList: function (saveHidden, total,  allSelect, noSelect, list) {
      this.saveHidden = saveHidden,
      this.totalPrice = total,
      this.allSelect = allSelect,
      this.noSelect = noSelect,
      this.goodsList = list
      var shopCarInfo = {};
      var tempNumber = 0;
      var list = [];
      shopCarInfo.shoplist = list;

      for (var i = 0; i < list.length; i++) {
        tempNumber = tempNumber + list[i].number
      }
      shopCarInfo.shopNum = tempNumber;
      wx.setStorage({
        key: "shopCarInfo",
        data: shopCarInfo
      })
    },

復制代碼

將(jiang)需要(yao)做本(ben)(ben)地存儲數據的方法(fa)封(feng)裝(zhuang)成一個(ge)方法(fa)模型,當需要(yao)做本(ben)(ben)地存儲時,直(zhi)接做引用(yong),如今vue、react中多用(yong)到的架構思想,都對模型層封(feng)裝(zhuang)有(you)一定的要(yao)求。

bindAllSelect() {
      var list = this.goodsList;
      var currentAllSelect = this.allSelect
      if (currentAllSelect) {
        list.forEach((item) => {
          item.active = false
        })
      } else {
        list.forEach((item) => {
          item.active = true
        })
      }
      this.setGoodsList(this.getSaveHide(), this.totalPrice(), !currentAllSelect, this.noSelect(), list);
    }


易優小程序(xu)(企業版)+靈(ling)活api+前(qian)后代碼開(kai)源 碼云(yun)倉庫:
本文地址://www.jinyoudianli.com/wxmini/doc/course/24661.html 復制鏈接 如需(xu)定制請聯系(xi)易優(you)客(ke)服咨詢:

工作日 8:30-12:00 14:30-18:00
周六(liu)及部分(fen)節假日提供值班(ban)服務

易小優
轉(zhuan)人工 ×