在 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"
}]
}
}
#pagePath 页面路径
#text tabBar文字信息
#iconPath tabBar图片路径
#selectedIconPath tabBar选中的图片路径
在pages的同级目录下新建images文件,在里面新建bar文件放图片
在app.json:
{
"pages": [
"pages/home/home"
],
...
}
pages 目录下,每个页面就是一个文件夹,一个页面包含wxml、wxss、js和json文件,其中:
wxml:相当于html文件
wxss:相当于css文件
#1、标签
标签分单双标签,书写格式与html完全一样,但在微信小程序里,没有div、span、p、h1-h6这些标签,它只有非常简单的两个最基本的标签:view(即:div) 与 text(即:span)。当然,还有其他经过封装的组件,我们后面会再做介绍。
#2、JavaScript
微信小程序与vue.js框架用法大致相同,同属MVVM框架,都是由数据驱动视图更新。因此,js事件和变量的书写,也会与原生JS稍有差异。
在 home.wxml 页面写入:
<view>{{msg}}view>
在 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
})
}
})
<view>
<view wx:for="{{list}}" wx:key="index">{{item}}view>
view>
wx:key可以不写,但会报警告
wx:key 的值有三种写法
1、wx:key=“property” ,其中property是代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。类似于字典的key值
2、wx:key=“*this”, 保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字
3、wx:key=“index”,代表每一项的索引
比较推荐*this
当有多个循环时,可以写wx:for-index=“inx”,wx:for-item=“items”,来区分每一个循环。
如
<view>
<view wx:for="{{list}}" wx:key="*this" wx:for-item="items" wx:for-index="ind">{{ind}} {{items}}
view>
view>
其中的ind为索引,items为数组每一项
wx:if 有更高的切换消耗,hidden有更高的初始渲染消耗
<view hidden="{{isShow}}">显示与隐藏view>
hidden与if相反,isShow的值为false的时候上面的view才会显示
data: {
isShow:false
}
bindtap 点击事件
bindinput 键盘输入事件
bindconfirm 回车事件
bindfocus 输入框聚焦事件
bindblur 输入框失焦事件
bindchange 值改变事件
触摸事件
bindtouchstart 动作开始
bindtouchend 动作结束
bindtouchmove 触摸移动
bindtouchcancel 触摸动作被打断
表单重置事件
<form bindreset="formReset" >
<button type="warn" form-type="reset">重置button>
form>
表单提交事件
<form bindsubmit="formSubmit"" >
<button type="primary" form-type="submit"">提交button>
form>
类似于vue的插槽
在pages > home 下新建文件夹 templates ,然后在里面新建test.wxml :
<template name="box1">
<view bindtap="btnFn">box1 :{{content}}view>
template>
<template name="box2">
<view bindtap="btnFn">box2 :{{content}}view>
template>
<template name="box3">
<view bindtap="btnFn">box3 :{{content}}view>
template>
在 home.wxml中:
<import src="./templates/test" />
<template is="box3" data="{{content: txt}}">template>
这里通过import标签引入模板,template标签使用模板,is属性指定对应的模板,data属性传值
在 home.js中:
Page({
data: {
txt: 999
},
btnFn() {
console.log('打印');
}
})
以上在需要使用模板的 home.js 里面定义了内容txt 和方法btnFn
WXS 代码可以编写在 wxml 文件中的 标签内,或以 .wxs 为后缀名的文件内。
模块
每一个 .wxs 文件和 标签都是一个单独的模块。
每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见。
一个模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现。
wxs写法1:
在 pages > home 文件夹下新建 tools.wxs 文件,并定义方法fn,通过module.exports 导出
function fn (a,b){
return a+b
}
module.exports ={
fn:fn
}
home.wxml 中 通过src属性引入模块,module属性定义当前模块名称
<wxs src="./tools.wxs" module="foo">wxs>
<view>{{foo.fn(1,4)}}view>
写法二:
在home.wxml 中:
<wxs module="koo">
function add (val){
var a = val + 1
return a
}
module.exports={
add:add
}
wxs>
<view >{{koo.add(0)}}view>
和创建页面一样,只是把pages改成components
新增 “components/product/product”
{
"pages": [
"pages/home/home",
"components/product/product"
],
.....
}
在product.wxml中:
写好页面结构
<view class="product_list">
<view wx:for="{{showArr}}" wx:key="*this" class="product_list_box">
<image class="img" src="{{item.imgSrc}}">image>
<view class="txt">{{item.imgTxt}}view>
view>
view>
在product.js中:
写好数据,图片我放在images文件下的home文件
// 注意注意:这里的Page()方法改成了Component()方法
Component({
data: {
showArr: [{
imgTxt: "卡布奇诺",
imgSrc:"../../images/home/logo1.jpg"
},
{
imgTxt: "白咖啡",
imgSrc:"../../images/home/logo2.jpeg"
},
{
imgTxt: "拿铁咖啡",
imgSrc:"../../images/home/logo3.jpeg"
}
]
},
})
在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 #ccc;
border-radius: 10rpx;
overflow: hidden;
margin-bottom: 20rpx;
}
.product_list_box .img{
width: 100%;
display: block;
height: 280rpx;
}
.product_list_box .txt{
height: 50rpx;
line-height: 50rpx;
text-align: center;
background-color: #eee;
}
在product.json中:
声明组件 “component”: true
{
"usingComponents": {},
"component": true
}
在home.json 中:
注册组件
{
"usingComponents": {
"product-block": "/components/product/product"
}
}
在home.wxml 中 :
引入组件
<product-block />
或:
<product-block>product-block>
考虑到组件需要复用,那么数据应该在父组件传过来。
父传子
我们将该组件的数据迁移到父组件 Home.js 中,然后通过父传子传过来:
父组件
在home.wxml :
<product-block showArr="{{showArr}}" >product-block>
在home.js :
Page({
data: {
showArr: [{
imgTxt: "卡布奇诺",
imgSrc: "../../images/home/logo1.jpg"
},
{
imgTxt: "白咖啡",
imgSrc: "../../images/home/logo2.jpeg"
},
{
imgTxt: "拿铁咖啡",
imgSrc: "../../images/home/logo3.jpeg"
}
]
}
})
子组件
在product.js :
Component({
//通过properties接收父组件传过来的值,类似于vue的props
properties:{
showArr:{
//定义数据类型
type:Array,
//定义数据的初始值
value:[]
}
}
})
子传父
我们可以通过子组件的自定义事件this.triggerEvent ,点击product 组件中的任意一项,来触发父组件的事件。
子组件
在product.wxml :
<view class="product_list">
<view wx:for="{{showArr}}" wx:key="*this" class="product_list_box" bindtap="productFn">
<image class="img" src="{{item.imgSrc}}">image>
<view class="ve">{{item.imgTxt}}view>
view>
view>
在product.js :
Component({
//组件中写方法需要写上methods
methods:{
productFn(){
//子传父通过triggerEvent, 类似vue的$emit
this.triggerEvent('eventFn','触发了事件')
}
}
})
父组件
在home.wxml :
<product-block showArr="{{showArr}}" bind:eventFn="homeEvent">product-block>
在home.js :
Page({
...,
// 页面无需写methods
homeEvent(val) {
console.log(val.detail);
}
})
点击之后,控制台打印了 :触发了事件。
定义全局变量globalData,在app.js中:
// app.js
App({
globalData: {
name: '张三'
}
})
调用的方法有:
【方法一(推荐)】通过调用app获取,需要在第一行声明app的实例
const app = getApp()
Page({
onLoad: function () {
console.log(app.globalData.name);
},
})
【方法二】直接通过getApp().globalData获取,不需要写const app = getApp()实例
Page({
onLoad: function () {
console.log(getApp().globalData.name);
},
})
修改global的方法【借助方法一】:
app.globalData.name = "李四";
1、跳转到非tabBar 的页面(js)
wx.navigateTo({
url: '/pages/nav/nav'
})
// url携带参数的形式:
wx.navigateTo({
url: '/pages/nav/nav?pid=123',
})
// 如何获取参数?
onLoad: function (options) {
console.log(options.pid) // 123
},
// 携带复杂参数的形式
wx.navigateTo({
url: '/pages/nav/nav?pid=123',
//跳转成功,通过eventChannel向被打开页面传送数据
success:function(res){
res.eventChannel.emit('pageInfo',{name:'用户'})
}
})
// 接收复杂参数的形式
onLoad: function (options) {
console.log(options.pid); //123
const channel = this.getOpenerEventChannel()
//使用getOpenerEventChannel()方法,通过.on方法获取
channel.on('pageInfo',function(data){
console.log(data); //{name: "用户"}
})
},
// 当前页反向发射数据到上一页
onLoad: function (options) {
const channel = this.getOpenerEventChannel()
//使用getOpenerEventChannel()方法,通过.emit方法触发
channel.emit('fanxiang',{arr:[11,22,33]})
},
// 上一页接收反向发射的数据
wx.navigateTo({
url: '/pages/nav/nav?pid=123',
// events中写反向发射的函数
events:{
fanxiang(res){
console.log(res.arr); //[11,22,33]
}
}
})
2、跳转到非tabbar页面(wxml)
<navigator url="/pages/logs/logs">navigator>
3、跳转到tabbar页面(js)
wx.switchTab({
url: '/pages/user/user'
})
页面生命周期
onLoad > onShow > onReady >onHide > onShow > onUnload
组件生命周期
Component({
lifetimes: {
created : function() {
// 在组件实例刚刚被创建时执行 1.6.3版本以上
},
attached: function() {
// 在组件实例进入页面节点树时执行 1.6.3版本以上
},
detached: function() {
// 在组件实例被从页面节点树移除时执行 1.6.3版本以上
},
ready: function() {
// 在组件在视图层布局完成后执行 1.6.3版本以上
},
moved: function() {
// 在在组件实例被移动到节点树另一个位置时执行 1.6.3版本以上
}
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
// ...
})
组件所在页面的生命周期:
Component({
pageLifetimes: {
show: function() {
// 页面被展示 2.2.3版本以上
},
hide: function() {
// 页面被隐藏 2.2.3版本以上
},
resize: function(size) {
// 页面尺寸变化 2.4.0版本以上
}
}
})