小程序指南

2020-05-08  本文已影响0人  A郑家庆

小程序代码构成

JSON配置

JSON是一种数据格式,并不是编程语言,在小程序中,JSON扮演的是静态配置的角色.

小程序配置app.json

app.json是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部tab等.
1.pages---用于描述当前小程序所有页面路径,这是为了让微信客户端知道当前你的小程序页面定义在哪个目录,文件名后面不需要写文件后缀.
2.window---用于设置小程序的状态栏、导航条、标题、窗口背景色.
3.tabBar---指定tab栏的表现,以及tab切换时显示的对应页面.
4.networkTimeout---各类网络请求的超时时间,单位均为毫秒.
5.debug---可以在控制台看到打印的日志
6.usingComponents---在此处声明的自定义组件视为全局自定义组件,在小程序内的页面或自定义组件中可以直接使用而无需再声明.
7.sitemapLocation---用来指明sitemap.json的位置;默认为sitmap.json即在app.json同级目录下名字的sitemap.json文件,sitemap.json文件用于配置小程序及其页面是否允许被微信索引.

配置文档:https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html

页面路由

在小程序中所有页面的路由全部由框架进行管理.框架以栈的形式维护了当前的所有页面.栈主要是用来控制点击小程序左上角回退按钮时回退顺序,通过不断入栈、出栈来控制回退页面的顺序.

路由方式 页面栈表现
初始化 新页面入栈
打开新页面(navigateTo) 新页面入栈
页面重定向(redirectTo) 当前页面出栈,新页面入栈
页面返回(navigateBack) 页面不断出栈,直到目标返回页
Tab切换(switchTab) 页面全部出栈,只留下新的Tab页面
重加载(reLaunch) 页面全部出栈,只留下新的页面

开发者可以使用getCurrentPages()函数获取当前页面栈.

注意:

reLaunch和switchTab用途有点类似,只是reLaunch先关闭了内存中所有保留的页面,再跳转到目标页面,switchTab是先关闭所有非tabBar页面,再跳转到tabBar页面,用switchTab如果从tabBar页面1跳转到tabBar页面2,返回的时候就会返回1,但是用reLaunch就会跳出小程序

小程序页面栈详解

页面栈主要是用来控制返回页面的顺序.

什么是页面栈

一个小程序存在多个界面,所以渲染层存在多个WebView线程,一个WebView就是一个页面栈,页面栈保存对应页面的所有信息,最多不超过10条页面栈.当路由发生变化时页面栈也会做出对应的变化.

路由跳转的使用场景

参考文章:https://juejin.im/post/5d47d7326fb9a06af2385b00
总结:小程序的路由跳转有navigateTo、redirectTo、reLaunch、switchTab这4种前进方式,返回有navigateBack这一种方式,返回的页面顺序是由页面栈决定的,前进的4种方式就是修改页面栈

WXML语法参考

数据绑定

// 内容
<view> {{ message }} </view>
// 组件属性
<view id="item-{{id}}"> </view>
// 控制属性
<view wx:if="{{condition}}"> </view>
// 关键字
<checkbox checked="{{false}}"> </checkbox>
// 三元运算
<view hidden="{{flag ? true : false}}"> Hidden </view>
// 算数运算
<view> {{a + b}} + {{c}} + d </view>
// 逻辑判断
<view wx:if="{{length > 5}}"> </view>
// 字符串运算
<view>{{"hello" + name}}</view>
// 数据路径运算
<view>{{object.key}} {{array[0]}}</view>
// 数组
<view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
// 对象
<template is="objectCombine" data="{{for: a, bar: b}}"></template>
// 扩展运算符
<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>

写template模版、component组件是传值,传的是一个对象,其他的是取值,两者是不一样的

列表渲染

<view :wx:for="{{array}}" wx:key="index">
  {{index}} : {{item.message}}
</view>

array可以是数组也可以是字符串,默认数据的当前项下标变量名默认为index,数组当前项的变量名默认为item,列表渲染一般都需要添加wx:key

<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
  {{idx}} : {{itemName.message}}
</view>

使用wx:for-item可以指定数组当前元素的变量名
使用wx:for-index可以指定数组当前下标的变量名

<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i">
  <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j">
    <view wx:if="{{i <= j}}">
      {{i}} * {{j}} = {{i * j}}
    </view>
  </view>
</view>
<block wx:for="{{[1, 2, 3]}}">
  <view> {{index}}: </view>
  <view> {{item}} </view>
</block>

wx:for也可以嵌套使用,也可以包裹在block标签中,以渲染一个包含多节点的结构块,block并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性,例如wx:if、wx:for

条件渲染

wx:if和v-if功能是一样的,hidden和v-show功能是一样的

template模版

小程序中组件化的实现有两种方式:template模版和component组件.这两种放别适用不同的场景.
1.template模版主要用于展示,模版中不涉及事件处理,需要处理的事件逻辑放在调用模版的页面中.一个template模版只包含wxml.wxss文件.
2.component组件作为一个单独的功能模块,不仅可以包含页面展示还可以包含该模块的事件逻辑处理,像一个单独的页面,component组件可以包含wxml、wxss、js、json文件.

template模版语法

一个template.wxml文件中适用<template>标签包含一个模版,一个template.wxml文件可以包含多个<template>模版,使用name属性作为模版的名称.
在模版中可以接受变量,使用{{}}展示,为变量的传递者由调用该模版的页面传递.

// index.wxml
<import src="./template.wxml">
<view>
   <template is="A" data="{{name}}">
   <template is="B" data="{{name, msg}}">
</view>
// 或者
<view>
   <template is="A" data="{{name, msg}}">
</view>
// index.wxss
@import "./template.wxss"

tempalte模版的引用需要使用<import>标签,该标签的src属性为引入模版的路径.import引用作用域是有限制的,引用页面只能使用被引用页面的模板,不能使用被引用页面中引用其它页面模板的模板
is属性用来区别模版文件中定义的模版名称,data是传入模版中的数据.
模版的样式需要在调用页面的wxss中单独引用template.wxss文件.

// template.wxml
<template name="A">
  <text>template name: {{name}}</text>
</template>
<template name="B">
  <text>template name: {{name}} {{msg}}</text>
</template>
// 或者
<template name="A">
  <template is="B" data="{{name, msg}}"></template>
</template>

我们可以看到模版中还可以嵌套模版,而且是可以多层嵌套.

模版中的事件处理

在模版中定义的事件,需要调用页面中执行

// template.wxml
<template name="A">
  <text bindtap="handleTap">{{name}}</text>
</template>
// index.js
Page({
  data: {},
  handleTap () {
    console.log('点击')
  }
})
include

include可以将目标文件除了<template/><wxs/>外的整个代码引入,相当于是拷贝到include位置,如:

<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>
<!-- header.wxml -->
<view> header </view>
<!-- footer.wxml -->
<view> footer </view>
template和include区别

小程序中有两种引用方式一种是直接引用include,通过它相当于把<templete/>标注的以外的代码全部copy过来当前位置,而import则是相反,它是只引用模板
最后总结就是import可以用来引用模板,在开发中可以避免相同模板的重复编写,而include适合引入组件文件
参考文章:https://blog.csdn.net/sinat_39343982/article/details/74095205
参考文章:https://www.jianshu.com/p/ead124a6b7cf

WXSS

WXSS具有CSS大部分特性.同时为了更适合开发微信小程序,WXSS对CSS进行了扩充以及修改.与CSS相比,WXSS扩展的特性有:

尺寸单位(rpx)

rpx可以根据屏幕宽度进行自适应,规定屏幕宽度为750rpx,比如在iphone6上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素,所以开发小程序都以iphone6作为标准

样式导入

WXS

WXS是小程序的一套脚本语言,结合WXML可以构建出页面的结构.
WXS可以在所有版本的小程序中运行,与JS是不同的语言而且跟JS代码是隔离的,WXS中不能调用其他JS文件中定义的函数,也不能调用小程序提供的API.

WXS模块

WXS代码可以编写在wxml文件中的<wxs>标签内,或以.wxs为后缀名的文件内,wxs代码是独立的,与其他代码是隔离的,都有自己独立的作用域,里面定义的变量和函数只能通过module.exports暴露出来
wxs文件有两个属性module:当前wxs标签的模块名
src:引用.wxs文件的相对路径

注意:<wxs> 模块只能在定义模块的 WXML 文件中被访问到。使用 <include> 或 <import> 时,<wxs> 模块不会被引入到对应的 WXML 文件中。
<template> 标签中,只能使用定义该 <template> 的 WXML 文件中定义的 <wxs> 模块。WXS和JS是不同的语言,它有自己的一套,可以看官网文档,里面的API和JS大部分相同.

WXS里面的函数接受2个参数,第一个是event,在原有的event的基础上加了event.instance对象,第二个参数是ownerInstance,它们都是ComponentDescriptor对象,具体使用如下:

<wxs module="wxs" src="./test.wxs"></wxs>
<view id="tapTest" data-hi="WeChat" bindtap="{{wxs.tapName}}"> Click me! </view>
**注:绑定的WXS函数必须用{{}}括起来**
function tapName(event, ownerInstance) {
  console.log('tap wechat', JSON.stringify(event))
}
module.exports = {
  tapName: tapName
}

ownerInstance包含了一些方法,可以设置组件的样式和class

WXS响应事件

因为小程序是由逻辑层和渲染层构成的,渲染层和逻辑层每次通信都需要通过微信客户端,如果频繁通信就会影响性能开销,所以为了减少通信的次数,让事件在渲染层响应推出了WXS,WXS 函数的除了纯逻辑的运算,还可以通过封装好的ComponentDescriptor 实例来访问以及设置组件的 class 和样式,对于交互动画,设置 style 和 class 足够了。WXS 函数的例子如下:

var wxsFunction = function(event, ownerInstance) {
    var instance = ownerInstance.selectComponent('.classSelector') // 返回组件的实例
    instance.setStyle({
        "font-size": "14px" // 支持rpx
    })
    instance.getDataset()
    instance.setClass(className)
    // ...
    return false // 不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault
}

event.instance 来表示触发事件的组件的 ComponentDescriptor 实例。ownerInstance 表示的是触发事件的组件所在的组件的 ComponentDescriptor 实例,如果触发事件的组件是在页面内的,ownerInstance 表示的是页面实例。
WXS主要用于自定义动画以及频繁、大量的逻辑运算,类似vue中的计算属性,WXS可能不支持es6语法

事件系统

target和currentTarget区别

target:指的是当前点击的组件
currentTarget:指的是事件捕获的组件

<view catchTap = "fetchImage">
  <image src="a.png" data-postId = "item.id">
</view>

上面这段代码,如果点击想获取自定义属性postId的值是这样的:

fetchImage (e) {
  var  id = e.target.dataset.postId
}

target指的是image
currentTarget指的是view
自定义数据使用data-开头

mark

可以使用mark来识别具有触发事件的target节点.此外,mark还可以用于承载一些自定义数据(类似于dataset),当事件触发时,事件冒泡路径上所有的mark会被合并,并返回给事件回调函数.

<view mark:myMark="last" bindtap="bindViewTap">
  <button mark:anotherMark="leaf" bindtap="bindButtonTap">按钮</button>
</view>

在上述 WXML 中,如果按钮被点击,将触发 bindViewTap 和 bindButtonTap 两个事件,事件携带的 event.mark 将包含 myMark 和 anotherMark 两项。

Page({
  bindViewTap: function(e) {
    e.mark.myMark === "last" // true
    e.mark.anotherMark === "leaf" // true
  }
})

mark 和 dataset 很相似,主要区别在于: mark 会包含从触发事件的节点到根节点上所有的 mark: 属性值;而 dataset 仅包含一个节点的 data- 属性值。

简易双向绑定

在WXML中普通属性的绑定是单向的,如果要实现双向绑定需要添加model:前缀:

<input model:value="{{value}}">

打括号中只能是一个单一字段的绑定,如:

<input model:value="值为  {{value}}">
<input model:value="{{a+b}}">
<input  model:value="{{a.b}}">

以上都是不支持的.

在自定义组件中传递双向绑定

// custom-component.wxml
<input model:value="{{myValue}}">
// custom-component.js
Component({
  properties: {
    myValue: String
  }
})

这个自定义组件将自身的myValue属性双向绑定到了组件内输入框的value属性上.

<custom-component model:my-value="{{pageValue}}"></custom-component>

在自定义组件中触发双向绑定更新

自定义组件还可以自己触发双向绑定更新,做法就是:使用 setData 设置自身的属性。例如:

// custom-component.wxml
<view bind:tap="update">更新数据</view>
// custom-component.js
Component({
  properties: {
    myValue: String
  },
  methods: {
    update: function() {
      // 更新 myValue
      this.setData({
        myValue: 'leaf'
      })
    }
  }
})

如果页面这样使用这个组件:

<custom-component model:my-value="{{pageValue}}" />

获取界面上的节点信息

WXML节点信息

// 创建一个查询对象
const query = wx.createSelectQuery()
// 选取查询节点,获取它距离显示区域的边界距离
query.select('#the-id').boundingClientRect(function(res) {
  res.top
  res.left
  ....
})
// 选择显示区域,用于获取显示区域的尺寸、滚动位置.滚动位置查询请求 ,节点必// // 须是scroll-view或者viewport
query.selectViewport().scrollOffset(function (res) {
  res.scrollTop
})
// 执行所有请求
query.exec()

WXML节点布局相交状态

用于监听两个或多个组件节点在布局位置上的相交状态.这一组API常用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见.
1.参照节点:监听的参照节点取它的布局区域作为参照区域.
2.目标节点:监听的目标节点
3.相交区域:目标节点和参照区域的相交区域
4.相交比例:相交区域占参考区域的比例
5.阀值:相交比例如果达到阀值,则会触发监听器的回调函数.
以下示例代码可以在目标节点(用选择器 .target-class 指定)每次进入或离开页面显示区域时,触发回调函数。

Page({
  onLoad () {
   // 创建交集观察者,指定页面显示区域作为参照区域,指定目标节点并开始监听相 
   // 交状态变化情况
    wx.createIntersectionObserver().relativeToViewport().observe('.target-class', 
       res => {
           res.intersectionRect // 相交区域
           // ...
       })
  }
})
上一篇下一篇

猜你喜欢

热点阅读