小程序基础
小程序构成
项目结构
| pages |
| utils |
| app.js |
| app.json |
| app.wxss |
| project.config.json |
| sitemap.json |
页面组成
WXML和HTML
标签不同
| HTML(div, sapn, img,a) |
| WXML(view,text,image,navigator) |
属性节点不同
| <a href="#"></a> |
| <navigator url="/pages/home/home"></navigator> |
提供类似vue的模板
WXSS 和 CSS
新增rpx尺寸单位
提供全局的样式和局部样式
- 全局 app.wxss
- 局部 页面文件的 .wxss
仅支持部分选择器
- .class 和 #id
- element
- 并集选择器 后代选择器
- :: after 和 :: before
通讯模式
渲染层和逻辑层之间的通信
逻辑层和第三方服务器之间的通讯
小程序组件
view
| <!--类似div--> |
| <view></view> |
横向滑动
| <scroll-view class="main" scroll-x> |
| <view>1</view> |
| <view>2</view> |
| <view>3</view> |
| </scroll-view> |
| .main{ |
| height: 100rpx; |
| width: 100rpx; |
| white-space: nowrap; |
| } |
| .main view{ |
| display: inline-block; |
| height: 100rpx; |
| width: 100rpx; |
| background: rgb(35, 190, 21); |
| } |
竖向滑动
| <scroll-view class="main" scroll-y> |
| <view>1</view> |
| <view>2</view> |
| <view>3</view> |
| </scroll-view> |
| .main{ |
| height: 100rpx; |
| width: 100rpx; |
| |
| } |
| .main view{ |
| |
| height: 100rpx; |
| width: 100rpx; |
| background: rgb(35, 190, 21); |
| } |
swiper和swiper-item 轮播图
| <swiper> |
| <swiper-item>A</swiper-item> |
| <swiper-item>B</swiper-item> |
| <swiper-item>C</swiper-item> |
| </swiper> |
| |
| indicator-dots |
| indicator-color |
| indicator-active-color |
| autopay |
| interval |
| circular |
text 文本
| |
| <text selectable>1393939393</text> |
rich-text 将渲染html字符串
| <rich-text nodes="<h1>qwe</h1>"></rich-text> |
小程序API
监听事件API
以on开头,来监听某些事件的触发
wx 类似window
wx.onWindowResize(function) 监听窗口是否变化
同步API
以sync结尾的API
执行的结果可以通过函数返回直接获取
异步API
需要通过success ,fail , complete接收调用的结果
WXML
数据绑定
.js里定义数据
| Page({ |
| |
| |
| |
| data: { |
| name: 'giao', |
| age: 18 |
| }, |
| }) |
.wxml 直接用
| <view>{{name}}</view> |
| <view>{{age}}</view> |
事件绑定
渲染层到逻辑层的通讯方式
可以将用户在渲染层的行为通过微信客户端反馈到逻辑层
常用
事件对象的属性列表
触发回调函数的时候, 会收到事件对象event
| type |
| target |
| currentTarget |
| detail |
bindtap 触摸事件
| Page({ |
| |
| |
| |
| data: { |
| count: 0 |
| }, |
| |
| |
| |
| countAdd(e){ |
| |
| console.log(e.target.dataset); |
| |
| this.setData({ |
| count: this.data.count + 1 |
| }) |
| }, |
| |
| |
| |
| onInputFn(e){ |
| console.log(e.detail.value); |
| this.setData({ |
| msg: e.detail.value |
| }) |
| }, |
| }) |
| |
| <button bindtap="countAdd" data-num="{{1}}">+1</button> |
| <input value="{{msg}}" bindinput="onInputFn" type="text" /> |
条件渲染
| <view wx:if="{{sex === 1}}">男</view> |
| <view wx:elif="{{sex === 2}}">女</view> |
| <view wx:else>妖</view> |
包裹性质的组件 ,不会在页面渲染, 可以控制多个组件显示隐藏
| <block wx:if="{{false}}"> |
| <view>block包裹</view> |
| <view>block包裹</view> |
| </block> |
hidden
隐藏元素
| <view hidden="{{true}}">block包裹</view> |
wx:if和hidden
列表渲染
| |
| <view wx:for="{{arr}}" wx:key="item"> |
| {{item}} |
| </view> |
小程序配置
全局配置
app.json
| pages |
| window |
| tabBar |
| style |
windiw
| "window":{ |
| |
| "backgroundTextStyle":"dark", |
| |
| "navigationBarBackgroundColor": "#345333", |
| |
| "navigationBarTitleText": "健康宝", |
| |
| "navigationBarTextStyle":"white", |
| |
| "enablePullDownRefresh" : true, |
| |
| "backgroundColor": "#efefef", |
| |
| "onReachBottomDistance": 50 |
| }, |
tabBar
用于实现多页面切换, 渲染顶部的时候不显示icon
最少渲染两个, 做多渲染5个
| "tabBar": { |
| |
| "backgroundColor": "#fff234", |
| |
| "color": "#fff", |
| |
| "borderStyle": "black", |
| |
| "list":[ |
| { |
| |
| "pagePath": "pages/nav/nav", |
| |
| "text": "nav", |
| |
| "iconPath": "/img/tabs/home.png", |
| |
| "selectedIconPath": "/img/tabs/home-active.png" |
| }, |
| {}, |
| {} |
| ] |
| }, |
页面配置
会覆盖全局配置, 跟 window一致
小程序数据请求
出于安全考虑, 小程序官方对数据接口的请求做出来两个限制
- 只能请求https类型的接口
- 必须将接口的域名添加到信任列表
| wx.request({ |
| url:'url', |
| method: 'get', |
| success: (res)=> { |
| console.log(res); |
| } |
| }) |
| wx.request({ |
| url:'url', |
| method: 'post', |
| data:{}, |
| success: (res)=> { |
| console.log(res); |
| } |
| }) |
视图与逻辑
声明式导航
页面上声明一个导航组件, 点击跳转
| |
| |
| |
| |
| |
| <navigator url="/pages/msg/msg" open-type="switchTab">配置tabBar</navigator> |
| |
| |
| |
| |
| |
| |
| <navigator url="/pages/info/info" open-type="navigate">配置没tabBar</navigator> |
| |
| |
| |
| |
| |
| |
| <navigator open-type="navigateBack" delta="1">返回</navigator> |
传参
| |
| |
| |
| |
| |
| |
| <navigator url="/pages/info/info?name=zs&age=18" open-type="navigate">配置没tabBar</navigator> |
编程式导航
调用小程序的导航API, 实现跳转
| wx.switchTab({ |
| |
| url:'', |
| |
| success: () =>{}, |
| |
| fail: ()=>{}, |
| |
| complete: ()=>{} |
| }) |
| |
| |
| |
| |
| onNavigator(){ |
| wx.switchTab({ |
| url:"/pages/msg/msg" |
| }) |
| }, |
| |
| |
| |
| |
| onNavigatorTo(){ |
| wx.navigateTo({ |
| url: '/pages/info/info' |
| }) |
| }, |
| |
| |
| |
| |
| |
| onBack(){ |
| wx.navigateBack({ |
| |
| delta: 1, |
| }) |
| }, |
| |
| <button type="primary" bindtap="onNavigator">编程式跳转tabBar</button> |
| <button type="primary" bindtap="onNavigatorTo">编程式跳转非tabBar</button> |
| |
| |
| <button type="primary" bindtap="onBack">返回</button> |
| |
传参
| |
| |
| |
| |
| onNavigatorTo(){ |
| wx.navigateTo({ |
| url: '/pages/info/info?name=zs&age=18' |
| }) |
| }, |
接收参数
| |
| |
| |
| onLoad(options) { |
| |
| console.log(options); |
| this.setData({ |
| query: options |
| }) |
| }, |
下拉刷新
全局 app.json window节点 enablePullDownRefresh: ture
局部 .json enablePullDownRefresh: true
| |
| |
| |
| onPullDownRefresh() { |
| this.setData({ |
| count: 0 |
| }) |
| |
| wx.stopPullDownRefresh({ |
| success: (res) => { |
| console.log(res); |
| }, |
| }) |
| }, |
上拉触底
"onReachBottomDistance": 50 距离底部50
| |
| |
| |
| onReachBottom() { |
| this.getColor() |
| }, |
loading显示隐藏
| wx.showLoading({ |
| title: '加载', |
| }) |
| wx.hideLoading() |
生命周期
应用生命周期
特指小程序从启动 运行 销毁的过程
页面生命周期
特指小程序, 每个页面的加载 渲染 销毁
| |
| |
| |
| |
| |
| onLoad(options) { |
| |
| }, |
| |
| |
| |
| |
| |
| onReady() { |
| |
| }, |
| |
| |
| |
| |
| |
| onShow() { |
| |
| }, |
| |
| |
| |
| |
| |
| onHide() { |
| |
| }, |
| |
| |
| |
| |
| |
| onUnload() { |
| |
| }, |
| |
| |
| |
| |
| onPullDownRefresh() { |
| |
| }, |
| |
| |
| |
| |
| onReachBottom() { |
| |
| }, |
| |
| |
| |
| |
| onShareAppMessage() { |
| |
| } |
wxs
数据类型
| number 数值类型 |
| string 字符串 |
| Boolean 布尔 |
| object 对象 |
| function 函数 |
| array 数组 |
| date 日期 |
| regexp 正则 |
语法
只支持普通函数 var定义 类似Es5 , 遵循commonJs
| <view>{{n1.giao('giao')}}</view> |
| |
| <wxs module="n1"> |
| module.exports.giao = function(str){ |
| return str + 123 |
| } |
| </wxs> |
可以写成wxs文件
| <wxs src="" module=""></wxs> |
自定义组件
创建组件
| 创建components文件夹 |
| 创建text文件夹 右键 点击新建Component |
引用组件
局部引用
只能在当前页面被引用
.json下添加
| { |
| "usingComponents": { |
| "text-01" : "/components/text/text" |
| } |
| } |
| |
| |
全局引用
可以再每个页面使用
app.json下添加
| { |
| "usingComponents": { |
| "text-01" : "/components/text/text" |
| } |
| } |
| |
| |
组件和页面的区别
- json 需要声明
"component": true,
- js 中调用 Component()
- 事件处理函数定义到methods
组件样式隔离
组件与页面之间互不影响
只有class会有样式隔离 , 不要使用Id , 属性, 标签选择器
修改样式隔离选项
| "styleIsolation": "isolated" |
| |
| |
| |
数据方法属性
| Component({ |
| |
| |
| |
| |
| properties: { |
| max: { |
| type: Number, |
| value: 10 |
| } |
| }, |
| |
| |
| |
| |
| data: { |
| |
| }, |
| |
| |
| |
| |
| methods: { |
| |
| } |
| }) |
| this.setData({ |
| |
| max: this.properties.max + 1 |
| }) |
数据监听器
| Component({ |
| observers: { |
| |
| '字段1,字段2.name':function(字段1,字段2){} |
| } |
| }) |
纯数据字段
| options:{ |
| |
| pureDataPattern: /^_/ |
| }, |
| |
| _data: true |
组件声明周期
| created |
| attached |
| ready |
| moved |
| detached |
| Component({ |
| |
| lifetimes: { |
| attached(){}, |
| detached(){} |
| } |
| }) |
组件在页面的声明周期
| Component({ |
| |
| pageLifetimes: { |
| show: function(){}, |
| hide: function(){}, |
| resize: function(size){}, |
| } |
| }) |
插槽
| |
| <slot></slot> |
| |
| |
| <text-01> |
| // 插槽内容 |
| 123 |
| </text-01> |
开启多个插槽
| options:{ |
| |
| multipleSlots: true |
| }, |
| <slot name="before"></slot> |
| <slot name="after"></slot> |
| |
| <text-01> |
| <text slot="before">before</text> |
| <text slot="after">after</text> |
| </text-01> |
通讯
属性绑定(父传子)
父向子传值, 只能传递普通类型的数据
| <text-01 count="{{count}}"></text-01> |
| properties: { |
| count: Number |
| }, |
事件绑定(子传父)
| |
| |
| |
| |
| this.triggerEvent('giao',{value:this.properties.count}) |
获取组件实例
可以获取组件的属性方法
| <button bindtap="getText">获取text</button> |
| const child = this.selectComponent('.text') |
| child.setData({ |
| count: child.properties.count + 1 |
| }) |
behaviors
实现组件间代码共享, 可以包含属性, 数据, 生命周期函数和方法
Behaviors/index.js
| module.exports = Behavior({ |
| |
| properties:{}, |
| |
| data: { |
| age:18 |
| }, |
| |
| methods:{} |
| }) |
| import Behavior from '../../Behaviors/index' |
| Component({ |
| behaviors: [Behavior], |
| }) |
npm包
Vant Weapp
小程序项目 直接安装 npm i @vant/weapp@1.3.3 -S --production
然后 点工具 构建npm
修改 project.config.json
| { |
| ... |
| "setting": { |
| ... |
| "packNpmManually": true, |
| "packNpmRelationList": [ |
| { |
| "packageJsonPath": "./package.json", |
| "miniprogramNpmDistDir": "./" |
| } |
| ] |
| } |
| } |
app.json 引入组件
| "usingComponents": { |
| "van-button": "@vant/weapp/button/index" |
| } |
| <van-button type="primary">测试按钮</van-button> |
API Promise化
官方提供的API都是基于回调函数实现的, 容易造成回调地狱
miniprogram-api-promise
| npm i --save miniprogram-api-promise@1.0.4 |
注意: 每一次安装完包都要构建npm
| import {promisifyAll} from 'miniprogram-api-promise' |
| const wxp = wx.p = {} |
| |
| promisifyAll(wx,wxp) |
| async getPromise(){ |
| const res = await wx.p.request({ |
| url: 'url', |
| method: 'get', |
| }) |
| console.log(res); |
| }, |
Mobx
| mobx-miniprogram |
| mobx-miniprogram-bindings |
| npm i mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1 |
store/index.js
| import {action, observable} from 'mobx-miniprogram' |
| |
| |
| export const store = observable({ |
| count1: 1, |
| count2: 2, |
| |
| get sum(){ |
| return this.count1 + this.count2 |
| }, |
| |
| updateCount: action(function (num) { |
| this.count1 = this.count1 + num |
| }) |
| }) |
页面使用
| import {createStoreBindings} from 'mobx-miniprogram-bindings' |
| import {store} from '../../store/index' |
| Page({ |
| countAdd(e){ |
| this.updateCount(e.target.dataset.num) |
| }, |
| |
| |
| |
| |
| onLoad: function (options) { |
| |
| this.storeBingings = createStoreBindings(this,{ |
| store, |
| |
| fields: ['count1','count2','sum'], |
| |
| actions: ['updateCount'] |
| }) |
| }, |
| |
| |
| |
| |
| onUnload: function () { |
| this.storeBingings.detroyStoreBindings() |
| }, |
| }) |
| <text>{{count1}}+{{count2}}={{sum}}</text> |
| <button type="primary" bindtap="countAdd" data-num="{{1}}">+1</button> |
| <button bindtap="countAdd" data-num="{{-1}}">-1</button> |
组件使用
| import {storeBindingsBehavior} from 'mobx-miniprogram-bindings' |
| import {store} from '../../store/index' |
| Component({ |
| behaviors: [storeBindingsBehavior], |
| storeBindings:{ |
| store, |
| fields:{ |
| count1: 'count1', |
| count2: 'count2', |
| sum: 'sum' |
| }, |
| actions:{ |
| updateCount: 'updateCount' |
| } |
| }, |
| methods:{ |
| countAdd(e){ |
| this.updateCount(e.target.dataset.num) |
| } |
| } |
| }) |
| <text>{{count1}}+{{count2}}={{sum}}</text> |
| <button type="primary" bindtap="countAdd" data-num="{{1}}">+1</button> |
| <button bindtap="countAdd" data-num="{{-1}}">-1</button> |
分包
什么是分包
把完整的小程序项目 , 按照需求划分成不同的子包 用户使用时按需加载
- 可以优化小程序首次启动的下载时间
- 多团队共同开发, 解耦协作
分包后项目构成
- 主包: 启动页面 + tabBer页面 , 一些公共资源
- 分包: 只包含和当前分包有关的页面资源
小程序启动时, 默认会下载主包并启动主包页面, 当用户进入分包的某个页面, 客户端会把对应分包下载下来, 进行展示
**注意: ** 整个小程序不能超过16M, 单包不能超过2M
使用分包
小程序会按 subpackages 的配置进行分包, subpackages 之外的目录将被打包到主包中
| |
| "subpackages":[ |
| { |
| "root": "text1", |
| "pages": [ |
| "pages/info/info" |
| ] |
| }, |
| { |
| "root": "text2", |
| "pages": [ |
| "pages/info/info" |
| ] |
| } |
| ], |
- 主包无法引用分包的私有资源
- 分包之间不能引用私有资源
- 分包可以引用公共资源
独立分包
普通分包依赖主包
独立分包独立运行 , 不能引用公共资源
| |
| "subpackages":[ |
| { |
| "root": "text1", |
| "pages": [ |
| "pages/info/info" |
| ], |
| "independent": true |
| } |
| ], |
分包预下载
进入指定页面, 下载需要用的分包
预下载大小限额2M
| "preloadRule": { |
| "pages/message/message":{ |
| |
| "network": "all", |
| |
| "packages": ["text1"] |
| } |
| }, |
自定义TabBar
配置信息 custom: true 是否开启自定义tabbar
app.json
| { |
| "tabBar": { |
| "custom": true, |
| |
| "list": [{ |
| "pagePath": "page/component/index", |
| "text": "组件" |
| }, { |
| "pagePath": "page/API/index", |
| "text": "接口" |
| }] |
| }, |
| "usingComponents": {} |
| } |
跟根目录添加custom-tab-bar 文件 新建Component
编写代码即可
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步