微信小程序学习笔记-基础
录屏工具:Snipaste
学习视频:黑马程序员微信小程序开发前端教程_零基础玩转微信小程序
开发文档:https://developers.weixin.qq.com/miniprogram/dev/framework/
环境准备
1、小程序开发工具:
https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
-
新建页面技巧:
-
pages 目录右键新建 page,会自动新建 json/js/wxml/wxss 四个文件,并且自动注册到 app.json
- app.json 配置 pages 保存,会自动创建页面
2、使用 vscode 开发微信小程序安装的插件:
-
wechat-snippet
微信小程序代码辅助,代码片段自动完成 -
minapp
微信小程序标签、属性的智能补全(同时支持原生小程序、mpvue 和 wepy 框架,并提供 snippets)
需要输入才会触发标签补全
输入空格会触发对应标签的属性补全 -
wxapp-helper
选择创建 wx 组件,自动生成配套的文件,简直不要太爽 -
小程序开发助手
-
插件 CSS Tree,html 结构生成 css 结构树
-
vscode 插件 easy less
-
wxml 高亮插件
3、Web Storm 设置小程序开发环境
settings -> Editor -> File Types -> 关联文件
VS Code 配置
工作区配置 .vscode/settings.json
{ "files.autoSave": "afterDelay", "minapp-vscode.prettyHtml": { "useTabs": false, "tabWidth": 2, "printWidth": 100, "singleQuote": false, "usePrettier": true, "wrapAttributes": false, "sortAttributes": false }, "less.compile": { "out": true, "outExt": ".wxss" } }
项目结构
app.js 全局入口文件 app.json 全局配置文件 app.wxss 全局样式文件 project.config.json 项目配置文件 sitemap.json 配置微信搜索 pages/ 页面文件夹 static/ 静态资源 components/ 自定义组件
全局配置文件 app.json
https://developers.weixin.qq.com/miniprogram/dev/framework/config.html
1、pages 页面路径列表
可以调整显示顺序
{ "pages": ["pages/home/home"] }
2、window 全局的默认窗口表现
{ "window": { // 下拉刷新文本风格: dark/light "backgroundTextStyle": "light", // 顶部导航背景颜色,仅支持HexColor "navigationBarBackgroundColor": "#fff", // 顶部导航文本 "navigationBarTitleText": "Weixin", // 顶部导航文本风格: black/white "navigationBarTextStyle": "black", // 开启下拉刷新 "enablePullDownRefresh": true } }
3、tabBar 底部 tab 栏
{ "tabBar": { "color": "#0094ff", "selectedColor": "#ff9400", "borderStyle": "white", "list": [ { "text": "首页", "pagePath": "pages/index/index", "iconPath": "icon/index_.png", "selectedIconPath": "icon/index.png" }, { "text": "我的", "pagePath": "pages/logs1/logs1", "iconPath": "icon/self_.png", "selectedIconPath": "icon/self.png" } ] } }
页面配置
对本页面的窗口表现进行配置
会覆盖 app.json 的 window 中相同的配置项
sitemap.json 配置
配置其小程序页面是否允许微信索引
数据绑定
核心:数据代理
Object.defineProperty(object, key, { get, set });
小程序: 初始化数据:data 修改数据:this.setData() 修改数据始终是同步的 数据流: 单向数据流:Model->View 简易数据双向绑定:model:value Vue 初始化数据:data 修改数据:this.key = value; 数据流: 单向数据流:Model->View 数据双向绑定:v-model React 初始化数据:state 修改数据:this.setState() 自身钩子函数是异步 非自身钩子函数(定时器回调)是同步 数据流: 单向数据流:Model->View
index.js
Page({ /** * 页面的初始数据 */ data: { name: 'Tom', age: 23, isShow: true, person: { name: 'Jack', age: 24, }, isChecked: true, }, });
index.wxml
text 相当于 span 行内元素 不会换行 view 相当于 div 块级元素 会换行 image 可以使用相对路径,也可以使用绝对路径
<!-- 1、字符串 --> <view>{{name}}</view> <!-- 2、数字 --> <view>{{age}}</view> <!-- 3、布尔值 --> <view>{{isShow}}</view> <!-- 4、对象 --> <view>{{person.name}}</view> <view>{{person.age}}</view> <!-- 5、标签属性中使用 --> <view data-age="{{age}}">{{age}}</view> <!-- 6、使用checkbox, 注意:"{{之间不能有空格 --> <checkbox checked="{{isChecked}}"></checkbox> <!-- 7、使用相对路径 --> <image src="../../static/img/logo.png"></image> <!-- 使用绝对路径 --> <image src="/static/img/logo.png"></image>
运算
1、表达式: 简单运算 1. 数字的加减 2. 字符串拼接 3. 三元运算符
2、运算:复杂的代码段 1. if else 2. switch 3. do while
<!-- 数字加减 --> <view>{{1 + 1}}</view> <!-- 字符串拼接 --> <view>{{"1" + "1"}}</view> <!-- 三元运算 --> <view>{{10 % 2 === 0 ? '偶数': '奇数'}}</view>
数组和对象循环
1、列表循环
wx:for="{{列表}}" wx:for-item="循环项的名称" wx:for-index="循环项的索引" wx:key="唯一值" 用来提高渲染渲染 wx:key="*this" 表示普通列表的循环项 eg: [1, 2, 3] 注意:数组嵌套循环不要重名 可以省略属性:`wx:for-item="item" wx:for-index="index"`
list: [ { id: 1, name: 'Tom', }, { id: 2, name: 'Jack', }, ];
<view wx:for="{{list}}" wx:for-item="item" wx:for-index="index" wx:key="id"> {{index}} - {{item.name}} </view>
1、对象循环
wx:for="{{对象}}" wx:for-item="对象的值" wx:for-index="对象的属性" 推荐:wx:for-item="value" wx:for-index="key"
person: { name: "Jack", age: 24 }
<view wx:for="{{person}}" wx:for-item="value" wx:for-index="key" wx:key="age"> {{key}} - {{value}} </view>
block 标签
占位符标签
写代码时候可以看到
渲染后会把它移除
类似 vue 中的 template
<block></block>
条件渲染
<!-- 标签不频繁切换 移除节点 --> <view wx:if="{{true}}">true</view> <view wx:elif="{{false}}">false</view> <view wx:else>default</view> <!-- 标签频繁切换 添加样式 display:none --> <view hidden>隐藏的内容</view> <view hidden="{{true}}">隐藏的内容</view>
事件绑定
事件流的三个阶段
- 捕获阶段:从外向内
- 执行目标阶段:
- 冒泡阶段:从内向外
父元素 -> 子元素 -> 父元素
- 冒泡事件: 该事件会向父节点传递
- 非冒泡事件
https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html
1、bind 不阻止冒泡
<view bind:tap="handleBindTap"> click me!</view>
2、catch 阻止冒泡
<view catch:tap="handleCatchTap">click me!</view>
示例:实现+1 和-1 操作
小程序模板中函数不支持传参
Page({ data: { num: 0, }, handleInput(e) { // 获取事件输出的值,并且更新数据 this.setData({ num: e.detail.value, }); }, handleTap(e) { // 获取data数据, this是当前实例 console.log(this.data.num); console.log(e); // 获取节点的传递参数 const num = e.currentTarget.dataset.num; // 设置data this.setData({ num: this.data.num + num, }); }, });
<!-- 绑定input事件 --> <input type="text" bindinput="handleInput" /> <view>{{num}}</view> <!-- 通过自定义属性传递参数 --> <button bindtap="handleTap" data-num="{{1}}">+</button> <!-- 或者冒号分隔 : --> <button bind:tap="handleTap" data-num="{{-1}}">-</button>
路由跳转
方法 | 说明 |
---|---|
wx.switchTab | 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 |
wx.reLaunch | 关闭所有页面,打开到应用内的某个页面 |
wx.redirectTo | 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。 |
wx.navigateTo | 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。 |
wx.navigateBack | 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。 |
配置文件页面路径 app.json
{ "pages": ["pages/home/home"] }
跳转需要使用绝对路径
wx.navigateTo({ url: '/pages/home/home', });
页面参数
- tabBar 页面的路径不能带参数
- 非 tabBar 的页面可以携带参数
path?key=value&key2=value2
尺寸单位 rpx
规定:屏幕宽度 750rpx
计算方式:
750px = 750rpx 1px = 1rpx iPhone6: 375px = 750rpx 1px = 2rpx 0.5px = 1rpx
公式:
page_width px = 750rpx 100px = ? 1 px = 750rpx / page_width 100 px = 100 * 750rpx / page_width => width px = width * 750 / page_width rpx
属性设置
width: calc(750rpx * 100 / 375);
flex 布局
flex子元素会自动设置为block元素
盒子内元素居中显示
<view class="box"></view>
.box { display: flex; align-items: center; flex-direction: column; }
样式引入
// 只能是相对路径 @import './common.css';
选择器和 less
样式重置 reset.less
/* 不支持通配符 error */ * { margin: 0, padding: 0, box-sizing: border-box; } /* 需要将*改为所有标签名 ok */ page, view, text, image { padding: 0; margin: 0; box-sizing: border-box; } /* 设置所有页面高度 */ page { height: 100% }
settings.json
"less.compile": { "outExt": "wxss" }
less 使用示例
// 定义变量 @color: yellow; // 使用变量 .text { color: @color; } // 引入 @import '../../style/reset.less'; .text { color: @themeColor; }
style/reset.less
// out: false // 不单独数输出 reset.css // 主题颜色 @themeColor: green;
常见组件
1、view 替代 div
2、text 文本标签,只能嵌套 text,长按可复制
- 长按复制: selectable
- 文本内容解码 decode
3、image 默认宽高: 320px * 240px
- mode 图片内容和宽高适配
- lazy-load 懒加载
4、swiper 轮播图
- 默认宽高:100% * 150px
- autoplay 自动轮播
- interval 间隔时间
5、navigator 导航组件
- 块级元素
- url 绝对路径/相对路径
- target self / miniProgram
- open-type 跳转方式
6、rich-text 富文本
7、button 标签
- size 尺寸
- type 颜色
- plain 镂空
- open-type 开放能力(手机号,个人信息,联系客服)
8、icon 图标
9、radio 单选框
10、checkbox 复选框
自定义组件
- Page 页面自定义函数放在 data 同层级下
- Components 组件自定义函数放在 methods 下
1、定义组件
目录结构
components/ tabs/ tabs.json tabs.js tabs.wxml tabs.less
tabs.json
{ "component": true }
tabs.js
Component({ // 接收父组件传递的参数 properties: { // 接收参数名 tabs: { // 数据类型 type: Array, // 默认值 value: null, }, }, // 组件数据 data: {}, methods: { /** * methods中绑定点击事件 获取被点击索引 获取原数组 对数组循环 每项改为false 单签项改为true */ handleTabItemTap(e) { // 获取索引 let index = e.target.dataset.index; // 向父组件传递点击事件 this.triggerEvent('change', { index }); }, }, });
tabs.wxml
<view class="tabs"> <view class="tab-title"> <block wx:for="{{tabs}}" wx:for-item="item" wx:for-index="index" wx:key="id" > <view class="tab-title-item {{item.isActive ? 'active': ''}}" bind:tap="handleTabItemTap" data-index="{{index}}" >{{item.name}}</view > </block> </view> <view class="tab-content"> <!-- 占位符 --> <slot></slot> </view> </view>
tabs.less
.tabs { .tab-title { display: flex; padding: 10rpx 0; .tab-title-item { flex: 1; display: flex; justify-content: center; align-items: center; position: relative; } .active { color: red; // border-bottom: 5rpx solid currentColor; } .active::after { // display: block; content: ''; position: absolute; bottom: 0; left: 0; width: 50%; height: 2rpx; transform: translateX(50%); background-color: currentColor; } } .tab-content { } }
2、页面中使用组件
目录结构
pages/ demo/ demo.json demo.js demo.wxml demo.less
demo.json
{ "usingComponents": { // 使用绝对路径查找组件 "Tabs": "/components/tabs/tabs" } }
demo.js
const app = getApp(); Page({ /** * 页面的初始数据 */ data: { num: 0, tabs: [ { id: 1, name: '首页', isActive: true, }, { id: 2, name: '新闻', isActive: false, }, { id: 3, name: '资讯', isActive: false, }, { id: 4, name: '关于', isActive: false, }, ], }, // 处理子组件传递的事件 handleTabItemTap(e) { console.log('handleTabItemTap', e); // 获取索引 let index = e.detail.index; // let item = e.target.dataset.item; // item.isActive = !item.isActive; // 获取数组,严谨的做法是重新拷贝一份数组, 该方法需自己实现 let tabs = app.$util.deepCopy(this.data.tabs); // 修改数组状态 tabs.forEach((item, idx) => { if (idx == index) { item.isActive = true; } else { item.isActive = false; } }); // 更新数据 this.setData({ tabs: tabs }); // 向父组件传递点击事件 }, });
demo.wxml
<!--pages/demo/demo.wxml--> <!-- 父组件向子组件传递数据 --> <Tabs tabs="{{tabs}}" bind:change="handleTabItemTap"> <block wx:if="{{tabs[0].isActive}}"> 0 </block> <block wx:elif="{{tabs[1].isActive}}"> 1 </block> <block wx:elif="{{tabs[2].isActive}}"> 2 </block> <block wx:elif="{{tabs[3].isActive}}"> 3 </block> </Tabs>
demo.less
// 没有样式
生命周期
APP 应用生命周期
app.js
App({ // 1、应用 第一次启动 onLaunch(){ // 获取用户个人信息 } // 2、应用 被看到 onShow(){ // 对应用数据重置 } // 3、应用 被隐藏 onHide(){ // 暂停或清除定时器 } // 4、应用 代码发生报错 onError(err){ // 收集代码报错信息 } // 5、应用 入口页面找不到 onPageNotFound(){ // 重定向到第二个首页 } })
Page 页面生命周期
Page({ // 页面初始数据 data: {}, // 页面加载 onLoad() { // 初始化页面数据, 发起网络请求 }, // 页面显示 onShow() {}, // 页面初次渲染完成 onReady() {}, // 页面隐藏 onHide() {}, // 页面卸载 onUnload() {}, // 下拉动作 onPullDownRefresh() {}, // 上拉触底 onReachBottom() {}, // 右上角分享转发 onShareAppMessage() {}, // 页面滚动 onPageScroll() {}, // 页面尺寸发生改变(横屏、竖屏) onResize() {}, // 点击当前页面的tabbar按钮 onTabItemTap() {}, });
Component 组件生命周期
Component({ created() {}, attached() { // 可以使用setData }, ready() {}, moved() {}, detached() {}, });