WeChat ミニ プログラム開発 コラムでは、WeChat ミニ プログラムの作成方法を詳しく説明します。

ミニ プログラムの歴史
WeChat ミニ プログラムとは何ですか?
WeChat ミニ プログラム。ミニ プログラムと呼ばれます。英語名はminiプログラム
で、ダウンロードやインストールをせずにそのまま利用できるアプリケーションです。彼は手の届くところにあった夢を達成した。ユーザーは、スキャンまたは検索することでアプリを直接開くことができます。
WeChat ミニ プログラムの理由
- WeChat には多数のユーザーがいます
- アプリや公式アカウントの宣伝コストが高すぎます
- 開発と適応のコストが低い
- 小規模での試行錯誤が容易で、すぐに反復できる
- クロスプラットフォーム
歴史
- 2016 年 1 月 11 日、張暁龍、WeChat は内部で新しいフォーム
申請番号
を研究し、その後その名前を 小プログラム
に変更しました。
- 2016 年 8 月 12 日に内部テストを開始
- 2017 年 1 月 9 日にオンライン化
#環境仕様
-
アカウント登録
mp.weixin.qq.com/ (アカウント情報---メールアクティベーション---情報登録)
-
ID取得
" class="lazyload" data-width="800" data- style="max-width:90%"/>
- #開発者ツールWeChat 開発者ツールのダウンロード
##ミニ プログラム開発者ツール
開発者ツールの紹介
ショートカット キー:
1 2 | 1. ctrl + shift + F (搜索)
2. alt + shift + F (代码格式化---VSCode)复制代码
|
ログイン後にコピー
" class="lazyload" data-width="800" data- style="max-width:90%"/>ミニ プログラム ネイティブ フレームワーク
ミニ プログラム ネイティブ フレームワーク、ミナ フレームワーク フレームワークの詳細
ミニ プログラム構成ファイル (WeChat 開発者ツールに構成ファイルを書き込みます。プロンプトが表示されます)
app.json グローバル構成ファイル-
1 2 3 4 5 | 配置全局文件
* pages:添加要创建的文件项,保存后就会自动生成文件
* [windows](https:
|
ログイン後にコピー
" class="lazyload" data-width="800" data- style="max-width:90%"/>
" class="lazyload" data-width="800" data- style="max-width:90%"/>
#page.json ページ構成ファイル
##サイトマップ
- #小規模プログラムのテンプレート構文WXML ---> HTML (基本コンポーネント、イベントシステム、ページ構造を作成するコンポーネントを組み合わせたもの)
# インラインと同等タグ、改行なし
ブロックレベル要素と同等、改行
データ バインディング- {{data}}
-
操作-->式(数値計算、文字列連結、三項式)
リストループ(wx:for) -
wx:keyがバインドされています配列内の唯一の属性 wx:key=
これは、配列が 通常の配列- であることを意味し、`
this` はループ項目です
1 2 3 | <view>
索引: {{ index }}
名称: {{ item.name }}</view>复制代码
|
ログイン後にコピー
##タグ ---> プレースホルダー タグ
条件付きレンダリング (wx:if) (wx:if、wx:elif、wx :else) (隠し属性は次のように表示されます)スタイルの追加)
- ラベルが頻繁に切り替えられない場合は if を使用し、頻繁に切り替えるには hidden を使用します
- イベント バインディング キーワード:バインド ( bininput、bindtap [クリックイベント]) イベントソースオブジェクトの値を取得します:
data のデータの値を取得します:
値を設定しますイベント ソース オブジェクトをデータに戻します:
1 2 3 | this.setData({
num: this.data.num + operation
});复制代码
|
ログイン後にコピー
イベント バインディングはパラメーターを直接渡すことはできません。パラメーターはカスタム属性を介して渡す必要があります ({{渡されたパラメーター}}):
1 2 3 4 5 6 7 8 9 | <button>+</button>
bandletap(e) {
const operation = e.currentTarget.dataset.operation;
this.setData({
num: this.data.num + operation
});
},复制代码
|
ログイン後にコピー
样式
尺寸单位
当屏幕宽度等于 750px 时,1px = 1rpx
当屏幕宽度等于375px时, 1px =0.5rpx
样式导入只支持相对路径
选择器(微信小程序不支持通配符)
小程序的内置组件
小程序中常用的布局组件:
1 | view,text,rich-text,button,image,icon,swiper,radio,checkbox等。复制代码
|
ログイン後にコピー
view标签 相当于 p标签
text标签 只能嵌套text标签 长按文字可以复制【selectable】(只有这个标签有这个功能) 可以对回车,空格进行编码 (decode)
-
image标签 (打包上线的大小不能超过2M,使用图片的时候统一使用外网图片)
图片存在默认的宽高(320px * 240px)
-
mode 决定 图片内容 和 图片标签 做适配
scaleToFill 默认值 不保持纵横比,拉伸至标签定义的宽高
aspectFit 保持宽高比,保证图片的长边完全显示(常用 轮播图)
aspectFill 短边完全显示
widthFix 宽度不变,高度自动变化,保持原宽高比不变
top,left,bottom,right 背景图定位
-
小程序中的图片 直接支持 懒加载
lazy-load 会自己判断 当图片出现在视口的上下三屏之内的时候,自己开始加载图片
-
swiper标签 ---》 轮播图
swiper高度 = swiper的宽度 * 图片的高度 / 原图的宽度
-
navigator 导航组件 (块级元素,默认换行)
1 | <navigator></navigator>复制代码
|
ログイン後にコピー
-
rich-text(富文本标签,将字符串解析成对应标签,相当于v-html)
-
button 按钮
大小(size:mini/default),颜色(type:default/primary/warn),是否镂空(plain),是否在文字前有加载loading(loading),开发能力(opentype)
开放能力(opentype):
-
concat 直接打开 客服对话 功能,需要在小程序的后台配置
- 将小程序的appid由测试号改为自己的appid
- 登录微信小程序官网,添加 客服 - 微信
share 转发当前小程序到微信朋友中 ,不能把小程序转发到朋友圈中
getPhoneNumber 获取当前用户的手机号码,结合事件来使用,不是企业的小程序账号 没有权限来获取用户的手机号码
getUserInfo获取用户的个人信息
launchApp在 小程序 中直接打开 app
-
openSetting 打开小程序内置的授权页面
只会出现用户点击过的权限
feedback 打开小程序内置的意见反馈页面
-
icon
type:类型 success,success_no_circle,info,warn,wating.success_no_circle,info,warn,waiting,cancel,downkload,search,clear
size:大小 number / string
color:颜色
-
radio 单选框
1 2 3 4 5 6 7 8 9 10 11 12 13 | <radio-group>
<radio>男</radio>
<radio>女</radio></radio-group><view>选中的是: {{ gender }} </view>data:{
gender: ""
},
handleChange(e) {
let gender = e.detail.value;
this.setData({
gender
})
}复制代码
|
ログイン後にコピー
-
checkbox 多选框
1 2 3 4 5 6 7 8 | <checkbox-group>
<checkbox>{{ item.name }} </checkbox></checkbox-group><view>选中的是: {{ checkedList }} </view>checkedList:[]
handleChange(e) {
let checkedList = e.detail.value;
this.setData({
checkedList
})
}复制代码
|
ログイン後にコピー
小程序的生命周期
应用生命周期
触发过程:
onLaunch -》 onShow
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | App({
onLaunch() {
}
onShow() {
}
onHide() {
}
onError() {
}
onPageNotFound() {
wx.navigateTo({ url: "/pages/demo02/index"
})
}
})复制代码
|
ログイン後にコピー
页面生命周期
onLoad -> onShow -> onReady
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Page({ data: {
}, onLoad: function (options) {
}, onShow: function () {
}, onReady: function () {
}, onHide: function () {
}, onUnload: function () {
}, onPullDownRefresh: function () {
}, onReachBotton: function () {
}, onShareAppMessage: function () {
}, onPageScroll: function () {
}, onResize: function () {
}, onTabItemTap: function () {
}
})复制代码
|
ログイン後にコピー
小程序自定义组件
步骤:
创建
-
声明(那个页面要使用自定义组件,就在那个页面的json文件中声明)
1 2 3 | { "usingComponents" : { "Tabs" : "../../components/Tabs/Tabs"
}
}复制代码
|
ログイン後にコピー
-
使用
注意:
页面的.js文件中,存放事件回调函数的时候,存放在data同层级下
组件的.js文件中,存放时间的回调函数的时候,存放在methods中
-
在小程序中不要直接通过this.data.x.
来修改数组的值(建议先拷贝一份数组,然后再对拷贝的数组进行修改)
1 | let tabs = JSON.parse(JSON.stringify(this.data.tabs));let tabs = this.data;复制代码
|
ログイン後にコピー
组件之间的传值
父组件向子组件传值
通过 标签的属性
来传递的:
-
父组件传递
-
子组件接收
1 2 3 4 5 6 7 8 | Component({
properties: {
aaa:{
type: String,
value: ""
}
}
});复制代码
|
ログイン後にコピー
-
子组件使用父组件中传递过来的数据
将接收过来的数据当作本身data中的数据来使用
1 | <view>{{ aaa }}</view>复制代码
|
ログイン後にコピー
子组件向父组件传值
通过事件
来传递的。
tab切换栏,点击切换。
- 绑定点击事件 需要在methods中绑定
- 获取被点击的索引
- 获取原数组
- 对数组循环
- 给每一个循环项 选中属性 改为 false
- 给 当前的索引 的 项 添加激活选中效果
- 点击事件触发的时候,触发父组件中的自定义事件同时传递给父组件
- this.triggerEvent("父组件自定义事件的名称",要传递的参数)
Tabs页面中:
1 2 3 | <view>{{ item.name }}</view><view>
<slot></slot></view>复制代码
|
ログイン後にコピー
子组件的js文件中:(这样写不能改变组件内部的数据,只是基于样式的改变,不是基于功能)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | methods: {
hanldeItemTap(e) {
const {index} = e.currentTarget.dataset;
this.triggerEvent( "itemChange" , {
index
})
}
}复制代码
|
ログイン後にコピー
在父组件中的自定义组件中添加自定义事件:
1 2 3 4 | <tabs>
<block>1</block>
<block>2</block>
<block>3</block></tabs>复制代码
|
ログイン後にコピー
父组件的js中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | data: { tabs: [
{ id: 1, name: "首页" , isActive: true
},
{ id: 2, name: "待发货" , isActive: false
},
{ id: 3, name: "待付款" , isActive: false
}
]
}
const {index} = e.detail;
let {tabs} = this.data;
tabs.forEach((v,i) => i===index?v.isActive=true:v.isActive=false);
this.setData({
tabs
})
}复制代码
|
ログイン後にコピー
其他属性
定义段 |
类型 |
|
描述 |
properties |
Object Map |
|
组件的对外属性,是属性名,是属性设置的映射表 |
data |
Object |
|
常用于父组件向子组件传值,子组件接收父组件的值 |
observers |
Object |
|
监听properties和data的数据变化 |
methods |
Object |
|
组件的方法 |
created |
Function |
|
组件的生命周期函数(组件实例刚刚被被创建时执行)此时不能调用setData |
attached |
Function |
|
组件实例进入页面节点树时执行 |
ready |
Function |
|
组件布局完成时执行 |
moved |
Function |
|
移动执行 |
detached |
Function |
|
移除执行 |
|
|
|
|
项目
- 首页
- 商品列表
- 购物车
- 授权页面
- 商品搜索
- 商品收藏
- 商品分类
- 商品详情
- 结算
- 订单列表
- 个人中心
- 意见反馈
小程序的第三方框架
- 腾讯 wepy 类似于 vue
- 美团 mpvue 类似于 vue
- 京东 taro 类似于 react
- 滴滴 chameleon
- uni-app 类似于 vue
- 原生框架 MINA
使用阿里字体图标库
在阿里图标官网,将要使用的图标,加入购物车
将图标,加入项目
小程序 pyg ---》 Font class(通过类的方式来使用图标) ---》 查看在线链接
在项目的styles文件夹中,创建iconfont.wxss
文件
打开链接,将链接中的内容复制到iconfont.wxss
文件中
-
使用字体图标库中的字体
-
在全局wxss文件中,引入wxss文件
1 | @import "./styles/iconfont.wxss" 复制代码
|
ログイン後にコピー
-
使用
tabBar
在app.json中配置
1 2 3 4 5 6 7 8 9 10 11 12 13 | tbaBar: { "color" : "" ,
"selectedColor" : "" ,
"backgroundColor" : "" ,
"position" : "" ,
"borderStyle" : "" ,
"list" : [
{ "pagePath" : "" ,
"text" : "" ,
"iconPath" : "" ,
"selectedIconPath" : ""
}
]
}复制代码
|
ログイン後にコピー
页面样式的初始化
注意:在小程序中是不支持 通配符(*)的
在app.wxss
文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | page,view,text,swiper,swiper-item,image,navigator {
padding: 0;
margin: 0;
box-sizing: border-box;
}
page {
--themeColor: #eb4500;
font-size: 28rpx;
}复制代码
|
ログイン後にコピー
使用主题颜色:
1 2 3 | view {
color: var (--themeColor);
}复制代码
|
ログイン後にコピー
头部
设置主题色:
1 2 3 4 | "window" : { "backgroundTextStyle" : "light" ,
"navigatorBarBackgroundColor" : "#2b4500" ,
"navigatorBarText" : "唯品会" ,
"navigatorBarTextStyle" : "white" ,
|
ログイン後にコピー
使用接口数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Page({ data: { swiperList: []
},
onLoad: function () {
wx.request({ url: '' ,
success: (result) => {
this.setData({ swiperList: result.data.message
})
}
});
}
})复制代码
|
ログイン後にコピー
请求报错(两种解决方法):
- 在小程序
详情
界面 勾选上 不校验合法域名,web-view(业务域名),TLS版本以及HTTPS证书
- 配置请求接口 见 8.7.将小程序请求的域名添加到后台
解决回调地狱的问题(es6的promise)
在项目的request文件夹中创建index.js
文件
通过封装方法,然后调用函数传递参数的方式来使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ajaxTime++;
wx.showLoding({ title: "加载中" , mask: true
}); return new Promise((resolve, reject) => {
wx.request({
...params, success: (result) => {
resolve(result);
}, faile: (err) => {
reject(err);
},
complete: () => {
ajaxTime--; if (ajaxTime === 0) {
wx.hideLoading();
}
}
});
});
}复制代码
|
ログイン後にコピー
使用封装好的请求方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | },
onLoad: function () {
this.getSwiperList();
},
getSwiperList() {
request({ url: 'htltps://api/zbtbs/home/swiperList' });
.then (result => { this.setData({ swiperList: result.data.message
})
});
}
})复制代码
|
ログイン後にコピー
将小程序请求的域名添加到后台
- 进入
微信公众平台
- 开发
- 开发设置
- 服务器域名
- 添加request合法域名
获取本地存储的数据
web中的本地存储 和 小程序中的本地存储的区别:
- 写代码的方式不一样
- web中:
- 存储方式:localStorage.setItem("key", "value");
- 获取方式: localStorage.getItem("key");
- 小程序中:
- 存储方式:wx.setStorageSync("key", "value");
- 获取方式:wx.getStorageSync("key", "value");
- 存的时候 有没有做类型转换
- web:不管存的数据是什么类型的数据,最后都会通过toString()方法转换为字符串类型的数据
- 小程序:不存在数据的类型转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | const Cates = wx.getStorageSync( "cate" );
if (!Case) {
this.setCates();
} else {
if ( Date .now() - Cates.time > 1000 * 10) {
this.getCates();
} else { this.Cates = Cates.data;
}
}
}
wx.setStorageSync( "cates" , {time: Date .now(),data: this.Cates});
}复制代码
|
ログイン後にコピー
定义公共的url
在request.js文件中,封装请求方法
1 2 3 4 5 6 7 8 9 10 11 12 13 | export const request=(params) => {
const baseUrl = "https://api.zbsb.cn/api/public"
return new Promise((resolve, reject) => {
wx.request({
...params, url: baseUrl + params.url;
success: (result) => {
resolve(result);
}, faile: (err) => {
reject(err);
}
});
});
}复制代码
|
ログイン後にコピー
小程序支持es7的async语法
在微信开发者工具中勾选es6转es5语法
在github里面下载regenerator库中的runtime.js
在小程序目录文件下新建文件夹/lib/runtime/runtime.js,将代码拷贝进去
-
在每一个需要使用async语法的页面js文件中,引入文件
1 | import regeneratorRuntime from '../lib/runtime/runtime' ;复制代码
|
ログイン後にコピー
使用asyn语法:
1 2 3 | async getCates() {
const res=await request({url: "/categories" });
}复制代码
|
ログイン後にコピー
小程序url传参
1 2 3 4 | onLoad: function (options) {
consol.log(options);
}复制代码
|
ログイン後にコピー
封装tab切换组件
封装的Tab组件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | properties: { tabs: Array, value: []
}
<style>
.tabs-title { display: flex;
padding: 15rpx 0;
}
.title-item { display: flex;
justify-content: center;
align-item: center;
flex: 1;
}
.active { color: red;
border-bottom: 1rpx solid red;
}
</style><view>
<view>
<view>
{{ item.value }} </view>
</view>
<slot></slot>
</view></view>methods: {
handleItemTap(e) {
const {index} = e.currentTarget.dataset;
this.triggerEvent( "tabsItemChange" , {index});
}
}复制代码
|
ログイン後にコピー
使用封装的Tab组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <block>1</block>
<block>2</block>
<block>3</block></tab>
bindtabsItemChange(e) {
const {index} = e.detail;
let {tabs} = this.data;
tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
this.setData({
tabs
});
}复制代码
|
ログイン後にコピー
滚动条触底事件(页面上滑事件)
滚动条触底,加载下一页数据
总页数 = Math.ceil(总条数 / 每页显示的数据数)
1 2 3 4 5 6 7 8 9 10 11 12 13 | const total = res.total;
this.totalPage = Math. ceil (total / this.QueryParams.pagesize);
this.setData({ goodsList: [...this.data.goodsList,...res.goods]
});
wx-stopDownRefresh();
}
if (this.QueryParams.pagenum >= this.totalPage) {
} else {
this.QueryParams.pagenum++; this.getGoodsList();
}
}复制代码
|
ログイン後にコピー
下拉刷新页面
- 触发下拉刷新事件(需要在页面的json文件中开启一个配置项)【enablePullDownRefresh: true,backgroundTextStyle: dark】
- 重置 数据 数组
- 重置页码 设置为1
- 重新发送请求
- 数据请求成功,手动关闭等待效果
1 2 3 4 5 6 | onPullDownRefresh() {
this.setData({ goodsList: []
});
this.QueryParams.pagenum=1;
this.getGoodsList();
}复制代码
|
ログイン後にコピー
wx.showModel改变this的指向问题
1 2 3 4 | wx.showModel({ title: '提示' , content: '您是否要删除?' , success :(res) => {
...
}
})复制代码
|
ログイン後にコピー
js中的删除
弹窗的封装
在asyncWX.js文件中
1 2 3 4 5 6 7 8 9 | export const showModel=({content}) => { return new Promise((resolve,reject) => {
wx.showModel({ title: '提示' , content: content, success :(res) > {
resolve(res);
}, fail :(err) => {
reject(err);
}
})
})
}复制代码
|
ログイン後にコピー
使用
1 2 3 4 | import {showModel} from '../../utils/asyncWx.js' ;async showTips() { const res=await showModel({content: '您是否要删除?' }) if (res.confirm) {
cart.splice(index, 1); this.setData(cart);
}
}复制代码
|
ログイン後にコピー
获取缓存中的数据
1 | wx.getStorageSync( "address" );复制代码
|
ログイン後にコピー
微信支付
- 企业账号
- 在企业账号的小程序后台中 必须 给 开发者添加上白名单
- 一个AppID可以绑定多个开发者
- 绑定之后的开发者就拥有了开发者的权限了
- 支付按钮
- 先判断缓存中有没有token
- 没有 跳转到授权页面 获取用户的 token 值
- 有 执行支付操作
流程:创建订单,准备预支付,发起微信支付,查询订单
一,获取token
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | handleOrderPay() { try {
const token = wx.getStorageSync( "token" );
if (!token) {
wx.navigateTo({ url: "/page/auth/index"
}) return ;
}
const header = {Authorization:token};
const order_price = this.data.totalPrice;
const consignee = this.data.address.all;
let goods = []; const cart = this.data.cart;
goods.forEach(v => goods.push({ goods_Id: v.goods_Id,
goods_number: v.goods_number,
goods_price: v.goods_price
})) const orderParams = {order_price,consignee,goods}
const {order_number}=await request({url: "/order/create" },method: "POST" ,data:orderParams,head:head});
const {pay}=await request({url: "/order/req_unifiedorder" ,method: "POST" ,head,data:{order_number}});
await requestPayment(pay);
const res=await request(url: "/orders/chkOrder" ,method: "POST" ,head,data:{order_number}});
await showToast({title: "支付成功" });
let newCart = wx.getStorageSync( "cart" );
newCart = newCart.filter(v => !v.checked);
wx.setStorageSync( "cart" ,newCart);
wx.navigateTo({ url: '/page/order/index'
})
} catch (err) { await showToast({title: "支付失败" });
}
}复制代码
|
ログイン後にコピー
page/autn/index页面中:
1 2 | <button>
获取授权</button>复制代码
|
ログイン後にコピー
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | const { encryptedData,rawData,iv,signature } = e.detail;
const {code} = await login(); const loginParams = { encryptedData, rawData, iv, signature, code }
const {token}=await request(url: '/user/wxlogin' ,data: loginParams,methods: "post" );
wx.getStroageSync( "token" , token);
wx.navigateBack({ data: 1
})
} catch (err) { console.log(err);
}
}复制代码
|
ログイン後にコピー
在asyncWX.js
文件中封装支付方法:
1 2 3 4 5 6 7 8 9 10 | export const requestPayment=(pay) => { return new Promise((resolve,reject){
wx.request({
...pay, success: (result) => {
resolve(result);
}, fail: (err) => {
reject(err);
}
})
})
}复制代码
|
ログイン後にコピー
二,准备预支付(获取参数 pay)
三,发起微信支付(提交pay参数)
四,查询订单
五,删除缓存中已经被选中购买的商品
六,删除后的购物车数据 填充会缓存
七,跳转页面
图片上传(wx.uploadFile)
图片上传的时候,存储上传的图片的时候,要先拼接上之前的图片。
chooseImage:[],
this.setData({
chooseImage: [上传之前的图片组, 上传的图片组]
chooseImage: [...this.data.chooseImage, ...chooseImage]
})
上传文件的api不支持多个文件同时上传
解决方法:遍历数组 挨个上传
1 2 3 4 | wx.uploadFile({ url: '' ,
filePath: '' ,
name: '' ,
formData: {},
|
ログイン後にコピー
项目发布
注意:发布之前记得关闭详情界面的 不校验合法域名
上传的每个文件大小不超过2M,总大小不超过10M。
上传:
- 版本号
- 第一个数字(大版本的更新)
- 第二个数字(重要功能更新)
- 第三个数字(最小功能,小bug,小补丁)
- less文件是不会被打包上传的
- 上传成功后的小程序还是一个体验版本的小程序,如果需要将体验版本的小程序变成线上版本的小程序,就在 微信公众平台将提交的体验本的小程序,提交审核(审核的时间大概是一个小时)。
小程序插件
小程序开发助手![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7znr3gju-1594264046886)(https://img.php.cn/upload/article/000/000/052/62154dd59d731a99e80263d5b4735b83-0.jpg Support/typora-user-images/image-20200707145006263.png)]](/static/imghw/default1.png)
-
安装easy less插件
在vscode中配置(ctrl + shift + p 然后输入 setting,然后添加上如下配置):
1 | "less.compile" : { "outExit" : ".wxss" }复制代码
|
ログイン後にコピー
相关免费学习推荐:微信小程序开发
以上が心配しないでください。WeChat ミニ プログラムの書き方を段階的に教えます。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。