今日学习目标
1、熟悉APPID与微信开发者工具使用
2、熟练配置项目与沉浸式导航栏
3、掌握数据绑定并能实现双向数据绑定
4、掌握列表渲染与条件渲染
5、了解模板使用
6、掌握WXS的使用
7、掌握组件化开发、组件传值方法
8、掌握路由跳转与tabbar页面跳转
9、掌握生命周期
10、掌握数据请求及封装
预:微信小程序账号注册与APPID获取【了解】
访问 http://mp.weixin.qq.com/ ,并点击 立即注册
:
点击:
然后填写邮箱和密码(记住:如果你的邮箱注册过微信公众号,请重新注册一个邮箱):
点击注册,并且登录邮箱去激活:
到邮箱中点击激活链接:
跳转到小程序官网后:
选择“个人”,然后按照要求填写:
扫码确认后,点击继续:
点击确定,就会跳转到小程序后台,这时候,点击左侧“开发”,再点击Tab栏“开发设置”,就可以获取到APPID了:
这个APPID只有自己能用,其他人是无法使用的。
一、微信小程序官网【了解】
https://mp.weixin.qq.com/
二、APPID注册【了解】
从官网这里进去:
选择小程序进行注册:
然后按照流程,填写好账号密码等信息即可。
若在填写过程中,需要你选择企业类型,请选择个人。
如果依然不知道要怎么操作,请查看《微信小程序账号注册与APPID》
三、获取APPID【掌握】
注册后,回到登录界面,登录刚刚注册的账号,进入系统后台,找到左侧的 开发
:
虽然我们的小程序在学习阶段,可以用测试号进行开发,但我们后期需要用到云开发,云开发要求必须有appid,因此,请尽快注册。
四、创建项目【掌握】
打开 微信开发者工具
(下载地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html),扫码后进入到这个界面:
点击此处,新建项目,按照以下图示填选:
点击 新建
,创建成功,进入到以下界面:
若未能进入此页面,请按快捷键 ctrl+R
重新编译一次即可。
五、工具与目录介绍【了解】
1、开发工具介绍
工具使用方法听讲师讲述即可。
2、目录介绍
我们先学习静态页面开发,再深入学习云开发。因此,我们目前只需要关注 miniprogram
目录下的内容即可。
六、项目总配置文件【重点】
打开 app.json
后,我们可以看到,所有的页面的创建,都在 pages
这个数组中填写:
其中,哪个页面地址写在数组的第一项,编译/刷新整个浏览器时,哪个页面就会优先显示。
1、创建页面
这里我们把pages下,所有页面都删掉,把这个 pages
字段也清空,我们自己来书写一个页面:
2、沉浸式导航栏
与 pages
同级的 window
对象,可用于控制整个小程序的沉浸式导航栏,但每个 页面也可单独配置。我们先配置整个小程序试试:
3、tabBar配置【重点】
这里提供tabbar配置所需要的图片:
链接: https://pan.baidu.com/s/1ZtYFpuE2HoacIKikyMeUnw 提取码: dm3i
在 app.json
中,windows
同级的位置,写入:
{
"windows": {
...
},
"tabBar": {
"color": "#909192",
"selectedColor": "#0600B8",
"list": [{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "images/bar/bar1_1.png",
"selectedIconPath": "images/bar/bar1.png"
},{
"pagePath": "pages/menu/menu",
"text": "菜单",
"iconPath": "images/bar/bar2_2.png",
"selectedIconPath": "images/bar/bar2.png"
},{
"pagePath": "pages/new/new",
"text": "新品",
"iconPath": "images/bar/bar3_3.png",
"selectedIconPath": "images/bar/bar3.png"
},{
"pagePath": "pages/kefu/kefu",
"text": "小二",
"iconPath": "images/bar/bar4_4.png",
"selectedIconPath": "images/bar/bar4.png"
}]
}
}
这里路径不允许使用 ./
开头。来看看效果:
七、配置Home页面【重点】
打开 home.json
文件,我们尝试隐藏导航栏:
八、页面文件介绍【掌握】
pages
目录下,每个页面就是一个文件夹,一个页面包含wxml、wxss、js和json文件,其中:
1、标签
标签分单双标签,书写格式与html完全一样,但在微信小程序里,没有div、span、p、h1-h6这些标签,它只有非常简单的两个最基本的标签:view(即:div) 与 text(即:span)。当然,还有其他经过封装的组件,我们后面会再做介绍。
2、JavaScript
微信小程序与vue.js框架用法大致相同,同属MVVM框架,都是由数据驱动视图更新。因此,js事件和变量的书写,也会与原生JS稍有差异。
九、数据绑定【重点】
在 home.wxml
页面写入:
在 home.js
写入:
Page({
data: {
msg: '你好,世界'
}
})
如此,便完成了数据绑定。
可以看到,动态变化的数据,我们统一放在data里面。这里跟vue做个区别,vue中规定组件内data必须是函数,而小程序不用,使用一个对象表示即可。
小程序中,我们要记住,凡是调用data中的数据,在wxml文件使用时,就需要加 {{}}
,这语法便是著名的:mustache语法,也称胡子语法。
十、双向数据绑定【重点】
1、修改data中的数据
小程序中,使用 this.setData()
来修改data中的数据。
2、方法绑定
一个标签需要调用一个函数(或称:方法),需要在标签上绑定事件,如绑定触摸事件(即:pc上的点击事件):
<button bindtap="tapFn">按钮</button>
然后在js中:
Page({
data: {
...
},
tapFn(){
// do something...
}
})
3、实现双向数据绑定
我们来实现双向数据绑定:
在 home.wxml
中:
<input value="{{msg}}" bindinput="iptFn"></input>
<view>{{msg}}</view>
在js中:
Page({
data: {
msg: '你好,世界'
},
// input值被修改时触发的函数
iptFn(e){
this.setData({
msg: e.detail.value
})
}
})
十一、列表循环【重点】
微信小程序实现for循环有好几种方式,一种是使用block标签来循环一段代码,当然,也可以直接在要循环的那段代码的外层,直接进行 wx:for
,看个人喜好。
<!-- 方法1 -->
<view class="box">
<view wx:for="{{arr}}" wx:key="*this">{{item}}</view>
</view>
<!-- 方法2 -->
<view class="box">
<block wx:for="{{arr}}" wx:key="*this">
<view>{{item}}</view>
</block>
</view>
js中:
Page({
data: {
arr: ['张三', '李四', '王五']
}
})
可以复制以上代码,到模拟器看看效果,会发现原来效果一样。
这里要注意几点:
保留关键字 *this
代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字;
每个循环都会自带 item
与 index
,不需要像vue一样写:v-for="(item, index) in arr"
;
如果出现多层数组的循环,那就会出现item指向不明确,虽然小程序可以帮我们自动识别,但代码可维护性降低,因此,我们可以使用 wx:for-item="items"
来改变item的名称。
十二、条件渲染【重点】
1、wx:if
在框架中,使用 wx:if=""
来判断是否需要渲染该代码块:
<view wx:if="{{condition}}"> True </view>
也可以用 wx:elif
和 wx:else
来添加一个 else 块:
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
2、block wx:if
因为 wx:if
是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 标签将多个组件包装起来,并在上边使用 wx:if
控制属性。
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
注意: block
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
3、wx:if
vs hidden
【了解】
因为 wx:if
之中的模板也可能包含数据绑定,所以当 wx:if
的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。
同时 wx:if
也是惰性的,如果在初始渲染条件为 false
,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。
相比之下,hidden
就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。
一般来说,wx:if
有更高的切换消耗而 hidden
有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden
更好,如果在运行时条件不大可能改变则 wx:if
较好。
4、总结
hidden
属性用于频繁切换,切换较少时,建议使用 wx:if
。用法:
wxml中:
<view hidden="{{ifShow}}">显示或隐藏</view>
js中:
Page({
data: {
ifShow: false // 由于hidden代表一种否定(或称:取反),所以这里为false,上面的view标签才能显示
}
})
十三、模板与引用【熟悉】
vue中有插槽的概念,小程序中有模板与引用,这两者还是比较像的。我们先来看看怎么玩。
1、模板创建
在 pages/home/
目录下创建 templates
文件夹,里面用于存放模板文件。我们新建 item.wxml
文:
<template name="box1">
<text bindtap="txtFn">box1: {{content}}</text>
</template>
<template name="box2">
<text bindtap="txtFn">box2: {{content}}</text>
</template>
2、模板引用
在 home.wxml
中:
<import src="./templates/item.wxml" />
<template is="box1" data="{{content: txt}}"></template>
这里通过import标签引入模板,通过template标签使用模板,使用is属性来指定调用 item.wxml
中哪个模板,使用data属性来传值。
这里大家要注意,创建模板时,我们写的 bindtap="txtFn"
,实现txtFn的方法,需要写在 调用方
的js文件中,而非模板的js文件。
// home.js
Page({
data: {
txt: '叩丁狼H5大前端'
},
// 可供模板调用的方法
txtFn(){
console.log('打印...')
}
})
十四、WXS模块【掌握】
WXS 代码可以编写在 wxml 文件中的 <wxs>
标签内,或以 .wxs
为后缀名的文件内。
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。
wxs可以说就是为了满足能在页面中使用js存在的,在wxml页面中,只能在插值 {{ }}
中写简单的js表达式,而不能调用方法,例如想取出一个字符串的最后一位,就不能调用slice()方法。
通常的解决办法是在page的data对象中先把这个字符串截取好赋给某个变量,然后在页面中使用这个变量,但是问题又来了,如果变量多了呢,是不是要定义很多次?wxs就是弥补了这样的短处。
相对来说wxml中使用js语法就比较薄弱了,wxs就是弥补了这样的短处。
1、使用方法
写好wxs文件 然后使用 module.exports
导出要使用的方法或变量
在待使用页面 使用 <wxs src="/path" module="tools" />
引入
在插值语法中使用 tools.method_name(para)
2、实用教程
* wxs写法1
在 home
页面下,新建 test.wxs
,并写一段截取字符串的方法:
function my_slice(str,a,b){
return str.slice(a,b);
}
module.exports = {
my_slice: my_slice
}
在wxml文件:
<wxs src="./test.wxs" module="tools" />
<view>
{{tools.my_slice("123456789",0,5)}}
</view>
* wxs写法2
在wxml文件:
<wxs module="tools">
function add(a, b){
var sum = a + b;
return sum;
}
module.exports = {
add: add
};
</wxs>
<view>
{{tools.add(3, 4)}}
</view>
十五、组件化开发【重点】
接下来的首页“新品展示”区块,我们采用组件化开发的操作:
1、创建组件
组件相当于页面,创建的方法与创建页面相同,可以在 app.json
中的 pages
进行创建:
{
"pages": [
...,
"components/product/product"
],
}
我们看到,在项目根目录中,增加了一个 components/product/product
目录。
2、结构、样式与数据渲染
product.wxml
中:
<view class="product_list">
<view wx:for="{{showArr}}" wx:key="*this" class="product_list_box">
<image src="{{item.imgSrc}}" mode="widthFix"></image>
<view>{{item.imgTxt}}</view>
</view>
</view>
product.wxss
中:
/* components/product/product.wxss */
.product_list{
display: flex;
padding: 20rpx 2%;
justify-content: space-between;
flex-wrap: wrap;
}
.product_list_box{
width: 49%;
box-shadow: 0 0 6rpx #666;
border-radius: 10rpx;
overflow: hidden;
margin-bottom: 20rpx;
}
.product_list_box image{
width: 100%;
display: block;
}
.product_list_box view{
height: 50rpx;
line-height: 50rpx;
text-align: center;
}
product.js
中:
// 注意注意:这里的Page()方法改成了Component()方法
Component({
data: {
showArr: [
{imgSrc: "/images/home/newPro1.jpg", imgTxt: "卡布奇诺"},
{imgSrc: "/images/home/newPro2.jpg", imgTxt: "白咖啡"},
{imgSrc: "/images/home/newPro3.jpg", imgTxt: "摩卡咖啡"},
{imgSrc: "/images/home/newPro4.jpg", imgTxt: "爱尔兰咖啡"},
{imgSrc: "/images/home/newPro5.jpg", imgTxt: "甜品咖啡"},
{imgSrc: "/images/home/newPro6.jpg", imgTxt: "意大利咖啡"},
{imgSrc: "/images/home/newPro7.jpg", imgTxt: "拿铁咖啡"},
{imgSrc: "/images/home/newPro8.jpg", imgTxt: "中式咖啡"}
]
},
})
3、声明为组件
在 product.json
中:
{
"usingComponents": {},
"component": true
}
4、调用组件
在 home.json
中:
{
"usingComponents": {
"product-block": "/components/product/product"
},
"navigationStyle": "custom"
}
在 home.wxml
中:
<product-block />
或:
<product-block></product-block>
十六、组件传值【重点】
虽然此时我们已经完成了组件化开发并引入成功,但我们要考虑数据是否放在子组件中,很明显这个子组件可能将来会被复用,因此数据应该由父级获取后传给子级,这样更加稳妥些。
1、父传子
我们将该组件的数据迁移到父组件 Home.js
中,然后通过父传子传过来:
Home.wxml
中:
<product-block showArr="{{showArr}}" />
product.js
中:
Component({
// properties用于接收传值,类似于vue中的props
properties: {
showArr: {
// 设置数据类型
type: Array,
// 设定初始值(即默认值)
value: [{imgSrc: "/images/home/newPro1.jpg", imgTxt: "卡布奇诺"}]
}
}
})
2、子传父
我们尝试点击 product
组件中的任意一项,来触发父级的事件。
<!-- 子组件wxml -->
<view class="product_list">
<view wx:for="{{showArr}}" wx:key="*this" class="product_list_box" bindtap="productTap">
...
</view>
</view>
// components/product/product.js
Component({
...,
// 如果是组件,不是页面,就必须写methods
methods: {
productTap(){
// 小程序中子传父通过triggerEvent来实现
this.triggerEvent('fatherEvent', 100);
}
}
})
父组件:
<!-- 标签上使用bind来接收子组件传过来的事件 -->
<product-block showArr="{{showArr}}" bind:fatherEvent="fatherEventFn" />
Page({
...,
// 页面无需写methods
fatherEventFn(data){
console.log(data.detail); // 100
}
})
如此,我们实现了父子传值。
3、全局变量globalData
微信小程序全局变量globalData在app.js中,调用的方法有:
【方法一(推荐)】通过app获取,需要在第一行声明app的实例 const app = getApp()
const app = getApp()
Page({
onLoad: function () {
console.log(app.globalData.name);
},
})
【方法二】直接通过getApp().globalData获取,不需要写const app = getApp()实例
onLoad: function () {
console.log(getApp().globalData.name);
},
【方法三】在app.js文件内使用
onLoad: function () {
console.log(this.globalData.name);
},
修改global的方法【借助方法一】:
app.globalData.name = "xxxx";
十七、路由跳转【掌握】
1、跳转到非tabbar页面(js)
wx.navigateTo({
url: '/pages/logs/logs'
})
// url携带参数的形式:
wx.navigateTo({
url: '/pages/logs/logs?id=123',
})
// 如何获取参数?
onLoad: function (options) {
console.log(options.id) // 123
},
// 携带复杂参数的形式
wx.navigateTo({
url: '/pages/logs/logs?id=123',
success: function(res) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('someData', { arr: [1,2,3] })
}
})
// 接收复杂参数的形式
onLoad: function (options) {
console.log(options.id) // 123
const eventChannel = this.getOpenerEventChannel() // 通过eventChannel来获取参数
eventChannel.on('someData', function(data) {
console.log(data.arr) // [1,2,3]
})
},
// 当前页反向发射数据到上一页
onLoad: function (options) {
const eventChannel = this.getOpenerEventChannel()
// 反向发射数据
eventChannel.emit('fanxiang', {username: '张三'});
},
// 上一页接收反向发射的数据
wx.navigateTo({
url: '/pages/list/list?id=123',
// events中写反向发射的函数
events: {
fanxiang(data){
console.log(data)
}
}
})
2、跳转到非tabbar页面(wxml)
<navigator url="/pages/logs/logs"></navigator>
3、跳转到tabbar页面
wx.switchTab({
url: '/pages/user/user'
})
十八、生命周期【重点】
微信小程序有两类生命周期,一类是组件的生命周期,另一类是页面的生命周期。
1、页面的生命周期:
总的来说,小程序页面的生命周期为:
onLoad > onShow > onReady > onHide > onShow > onUnload
2、组件生命周期
组件的生命周期:
Component({
lifetimes: {
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
}
})
这里提供组件的生命周期表:
这里有个要注意的点:
官方文档:
组件实例刚刚被创建好时, created
生命周期被触发。此时,组件数据 this.data
就是在 Component
构造器中定义的数据 data
。 此时还不能调用 setData
。 通常情况下,这个生命周期只应该用于给组件 this
添加一些自定义属性字段。
可以看出,在created中无法使用this,因此,建议不在created中做请求
再提供组件所在页面的生命周期:
代码示例:
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
十九、数据请求【重点】
1、原生API调用
在微信小程序中,我们使用 wx.request()
方法做数据请求,如:
wx.request({
url: 'http://kumanxuan1.f3322.net:8001',
success(res){
console.log(res);
}
})
接口地址:
叩丁严选项目接口文档 http://www.docway.net/project/1Ve70KqViGf/share/1Wi8PNyUmTA 阅读密码:zhaowenxian
2、合法域名配置
正常来讲,按照以上操作会碰到合法域名的报错,如:
这是因为小程序对接口地址有严格要求,所有的baseUrl必须在小程序后台配置合法域名。
到 mp.weixin.qq.com
登录,找到 开发
- 开发管理
- 开发设置
- 服务器域名
。只需要将后端给你的接口地址填写进去即可。这里注意:合法域名必须是https开头,否则无法配置,只能作为开发阶段的测试。
开发阶段想要测试,可以点击开发工具右上角的 详情
:
将 不校验合法域名
勾选上即可。
3、request封装
使用资料中封装好的request,其中有三个文件:
这里提供资料获取链接:
链接: https://pan.baidu.com/s/1BYzvpIbTlid_MLrh1RFA1g 提取码: 7gsl
request.js
是用来封装请求的,一般我们不动它
api.js
是用来统一管理Restful风格的接口地址与baseUrl的
fetch.js
是用来导出请求函数,供页面调用的,其中有3套模板,大家可以直接copy使用
二十、作业
参考 【硬核干货】小程序+Weapp自定义TabBar 做出tabbar。