常见内置组件
text
Text组件用于显示文本, 类似于span标签, 是行内元素
基本使用
<!-- 当文本最后是以\n结尾的时候,后边的text组件会换行显示 -->
<text>Hello Wolrd\n</text>
<text>Hello Wolrd\n</text>
user-select
<!--
user-select 文本是否可以长按选中
--- 该效果只能在实体机测试,模拟器无法测试该效果
--- 除了文本节点以外的其他节点都无法长按选中
--- 默认值为false
--- 该属性会使文本节点显示为 inline-block --- 即使以\n结尾也没有用(\n并不会被渲染出来)
--- 该属性用来替换已废弃的属性selectable
-->
<!-- user-select的值是boolean类型的值,所以设置值的时候需要使用mustache语法 -->
<text user-select="{{ true }}">Hello Wolrd\n</text>
<!-- 上面的写法可以简写为如下形式 -->
<text user-select>Hello Wolrd\n</text>
space
<text>Hello World\n</text>
<!-- nbsp --- 默认值 --- 自动根据字体设置空格大小 -->
<text space="nbsp">Hello World\n</text>
<!-- ensp --- 半个中文字符的大小 --- 比nbsp要大一点点 -->
<text space="ensp">Hello World\n</text>
<!-- emsp --- 一个中文字符的大小 -->
<text space="emsp">Hello World\n</text>
decode
<!-- decode --- 对实体字符( < > & '    )进行解析 -->
<text decode>2 < 5</text>
button
具体配置选项可以查看文档
<!-- 基本使用 --- 默认是块级元素 -->
<button>click me</button>
<!--
size属性 --- 按钮在块级元素和行内元素之间进行切换
--- default --- 块级元素 --- 默认值
---- mini --- 行内元素
-->
<button size="mini">click me</button>
<!--
type --- 按钮默认提供的样式
--- primary --- 绿色
--- default --- 默认值 --- 灰色
--- warn --- 红色
-->
<button type="primary">click me</button>
<!-- plan --- 镂空效果 -->
<button plain>click me</button>
<!-- disabled --- 禁用 -->
<button disabled>click me</button>
<!-- loading --- 是否存在加载icon -->
<button loading>click me</button>
<!-- hover-class --- 按钮被按下的时候显示的样式 -->
<!--
在home.wxss中设置的对应样式
.hover {
color: white;
background-color: blue;
}
-->
<button hover-class="hover">click me</button>
view
视图组件(块级元素,独占一行,通常用作容器组件) --- 相对于html中的div元素
具体配置选项可以查看文档
<!-- 基本使用 -->
<view>view组件</view>
<!--
hover-class --- 按下去显示的样式
hover-start-time --- 按住后多久出现点击态,单位毫秒
hover-stay-time --- 手指松开后点击态保留时间,单位毫秒
hover-stop-propagation --- 指定是否阻止本节点的祖先节点出现点击态
--- hover-stop-propagation阻止的是点击态的传递,并不会阻止事件的冒泡
-->
<view
class="outer"
hover-class="outer-hover"
hover-start-time="{{ 100 }}"
hover-stay-time="{{ 0 }}"
>
<view
class="inner"
hover-class="inner-hover"
hover-stop-propagation
>
view组件
</view>
</view>
image
Image组件用于显示图片
具体配置选项可以查看文档
<!-- 1.image的基本使用 -->
<!--
重点:
1.image组件可以写成单标签,也可以修成双标签 --- 单标签的时候必须有闭合符号
2.image组件默认有自己的大小: 320x240
3.image组件时一个行内块级元素(inline-block)
-->
<image />
<!-- 2.src: 本地路径(相对路径/绝对路径)/远程地址 -->
<image src='../../assets/detail/shop.png'/>
<!-- 对于绝对路径 --- 根目录对应的是项目的根目录 -->
<image src='/assets/detail/shop.png'/>
<!-- 网络图片 -->
<image src='https://res.wx.qq.com/wxdoc/dist/assets/img/0.4cb08bb4.jpg'/>
<!--
webp --- 默认不支持webp图片 --- 如果需要支持 需要手动开启
binderror --- 当错误发生时触发,event.detail = {errMsg}
bindload --- 当图片载入完毕时触发,event.detail = {height, width}
-->
<image
src='https://res.wx.qq.com/wxdoc/dist/assets/img/0.4cb08bb4.jpg'
bindload="handleLoad"
/>
<!-- 选取相册中图片 -->
<button bindtap='handleChooseAlbum'>选中图片</button>
<image src="{{imagePath}}"/>
Page({
data: {
imagePath: ''
},
handleLoad(e) {
console.log(e.detail)
},
handleChooseAlbum() {
// 选择相册中的图片 或 拍照选取图片(真机)
wx.chooseImage({
// 最多可以选取9张
count: 9,
// 使用箭头函数,以保证内部使用的this指向正确
success: res => {
this.setData({
imagePath: res.tempFilePaths[0]
})
}
})
}
})
<!--
lazy-load: 图片的懒加载
--- 在即将进入一定范围(上下三屏)时才开始加载
--- 也就是在可视窗口的上边和下边都有一个一样宽度和高度的窗口
--- 当图片进入到这个范围的时候,图片会自动开始加载操作
-->
<image
wx:for="{{10}}"
wx:key="item"
src="https://res.wx.qq.com/wxdoc/dist/assets/img/0.4cb08bb4.jpg"
bindload='handleImageLoad'
lazy-load
/>
<!--
4.show-menu-by-longpress: 长按图片显示发送给朋友、收藏、保存图片、识别小程序码的菜单
识别小程序码的菜单 --- 模拟器上会根据图片中有没有小程序码自动识别是否需要显示
在模拟器中点击是没有任何作用的,测试需要在真机上执行
-->
<image
show-menu-by-longpress
src="https://res.wx.qq.com/wxdoc/dist/assets/img/0.4cb08bb4.jpg"
/>
mode
mode选项可以设置,图片在image组件中的图片裁剪、缩放的模式,具体可以设置的值和示例可以查看文档
input
具体配置选项可以查看文档
<!--
1.基本使用
--- 默认背景色是透明的,而且没有边框,所以可能没有显示效果,但它是真实存在的
--- 其也可以设置单标签 或者 设置为 双标签
-->
<input />
<!-- 2.value: input中的默认值 --- 虽然文档说是必传的,但是不设置也是可以的,默认值就是空字符串 -->
<input value='哈哈哈'/>
<!--
3.type: 决定键盘类型(文本输入键盘/数字/身份证/带小数点的数字键盘/昵称输入键盘)
--- 默认值 text --- 文本输入键盘
--- 需要在真机进行测试
--- 如果类型是safe-password的时候,需要根据官方文档教程对秘钥进行配置,在传输内容的时候其会自动将内容进行加密操作
-->
<input type='number'/>
<!-- 4.password: 是否使用暗文显示 -->
<input password/>
<!-- 5.placeholder: 占位文字 -->
<input placeholder='请输入内容'/>
<!--
confirm-type --- 设置键盘右下角按钮的文字,仅在type='text'时生效
可选值为 --- send/search/next/go/done --- 默认值为done
-->
<input type="text" confirm-type="search" />
事件绑定
<!-- 6.input绑定事件 -->
<input
bindinput='handleInput'
bindfocus='handleFocus'
bindblur='handleBlur'
bindconfirm="handleConfirm"
/>
Page({
handleInput(e) {
console.log('input', e.detail)
},
handleFocus(e) {
console.log('focue', e.detail)
},
handleBlur(e) {
console.log('blur', e.detail)
},
handleConfirm(e) {
console.log('confirm', e.detail)
}
})
scroll-view
<!--
默认情况下,scroll-view是不可以滑动的
如果需要滑动,需要加上scroll-x 或 scroll-y属性
如果不设置scroll-x 或 scroll-y的时候
scroll-view的特性和view是一致的
所以如果需要垂直滚动,最好为scroll-view设置一个高度
-->
<scroll-view class="container" scroll-y>
<view class="card" />
<view class="card" />
<view class="card" />
<view class="card" />
<view class="card" />
<view class="card" />
<view class="card" />
<view class="card" />
</scroll-view>
<scroll-view
class="container"
scroll-x
bindscrolltolower="scrolltolower"
bindscrolltoupper="scrolltoUpper"
bindscroll="handleScroll"
>
<view wx:for="{{ 10 }}" wx:key="item" class="card" />
</scroll-view>
Page({
scrolltolower(e) {
console.log('lower', e.detail)
},
scrolltoUpper(e) {
console.log('upper', e.detail)
},
handleScroll(e) {
console.log('scroll', e)
}
})
所有组件共有的属性
所有wxml标签(组件)都支持的属性称之为共同属性,有如下共同属性
<!--
hidden属性 只是为元素添加上了display为none
组件依旧会被解析和渲染
如果要组件完全不解析和渲染,推荐使用wx;if
-->
<view hidden>hidden</view>
WXML + WXSS + WXS
WXSS
页面样式的三种写法: 行内样式、页面样式、全局样式
三种样式都可以作用于页面的组件
如果在一个组件上同时拥有者三种样式,他们的优先级是: 行内样式 > 页面样式 > 全局样式
home.wxml
<!-- 行内样式 -->
<view style="color: red;" class="fontColor">样式</view>
home.wxss
/* 页面样式 */
.fontColor {
color: blue;
}
app.wxss
/* 全局样式 */
.fontColor {
color: gray;
}
wxss中的样式选择器的优先级和css中的样式选择器的优先级是一致的
样式引入
在某些情况下,我们可能会将样式分在多个wxss文件中,方便对样式的管理。
这个时候,我们就可以使用样式导入,来让单独的wxss生效
/*
使用@import进行导入
@import后跟需要导入的外联样式表的相对路径(或者绝对路 径也可以),用;表示语句结束。
*/
@import '/style/foo.wxss';
rpx
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx
在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
所以建议在开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准
.font {
/*
在iPhone6上 40rpx === 20px
*/
font-size: 40rpx;
}
总结: 假设页面的宽度为page px ---> page px = 750rpx ---> 1px=750 rpx/page
官方样式库
为了减少开发者样式开发的工作量,小程序官方提供了WeUI-WXSS基本样式库,具体使用方式可以查阅文档
WXML
mustache
WXML: 基本格式
- 类似于HTML代码: 比如可以写成单标签,也可以写成双标签
- 必须有严格的闭合: 没有闭合会导致编译错误
- 大小写敏感: class和Class是不同的属性
<button size="mini" bindtap="handleClick">click me</button>
<view class="foo {{ isActive ? 'active' : '' }}">foo</view>
Page({
data: {
isActive: false
},
handleClick() {
this.setData({
isActive: !this.data.isActive
})
}
})
.active {
color: red;
}
逻辑判断 wx:if – wx:elif – wx:else
<input value="{{ score }}" type="text" bindinput="handleInput" />
<view wx:if="{{ score > 80 }}">优秀</view>
<view wx:elif="{{ score > 60 }}">及格</view>
<view wx:else>不及格</view>
Page({
data: {
score: 0
},
handleInput(e) {
this.setData({
score: e.detail.value
})
}
})
hidden 和 wx:if 的区别:
hidden --- 为组件添加一个名为hidden的属性,并使其display的值为none
wx:if --- 如果值为false,那么组件对应的值压根就不会被渲染
如果一个组件的切换是非常频繁的时候,推荐使用hidden来隐藏元素。否则推荐使用wx:if来隐藏对应的元素
列表渲染 – wx:for
在组件中,我们可以使用wx:for来遍历一个数组 (字符串 - 数字)
- 默认情况下,遍历后在wxml中可以使用一个变量index,保存的是当前遍历数据的下标值
- 数组中对应某项的数据,使用变量名item获取
<!-- 遍历数组 --- item 和 index是默认提供的变量 -->
<view wx:for="{{ ['Klaus', 'Alex', 'Steven'] }}" wx:key="item">{{ index }} --- {{ item }}</view>
<!-- 字符串会被作为字符数组进行遍历 -->
<view wx:for="Klaus" wx:key="item">{{ index }} --- {{ item }}</view>
<!-- 数字会被作为从0开始依次递增的数组 如3会被识别为[0, 1, 2] -->
<view wx:for="{{ 10 }}" wx:key="item">{{ index }} --- {{ item }}</view>
<!-- *this表示的就是就是item,也就是循环遍历的每一个元素 -->
<view wx:for="users" wx:key="*this">{{ index }} --- {{ item }}</view>
<!--
如果遍历的是一个对象,且key是字符串的时候,那么这个字符串可以被认为是对象的属性
例如这里的id 对应的就是item.id
-->
<view wx:for="users" wx:key="id">{{ index }} --- {{ item }}</view>
block
某些情况下,我们需要使用 wx:if 或 wx:for时,可能需要包裹一组组件标签,这个使用我们就可以使用block标签来替代view等标签
block的功能类似于vue中的template或react中的fragment
<block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性( 如wx:if 或 wx: for )
block标签的好处
- 将需要进行遍历或者判断的内容进行包裹
- 将遍历和判断的属性放在block便签中,不影响普通属性的阅读,提高代码的可读性
- 相比
view,使用block进行包裹,可以提升性能
虽然wx:for在遍历的时候,为我们提供了默认的变量item和index,但是某些情况下,我们可能想使用其他名称,尤其是在出现多层遍历时,名字重复的时候
这个时候,我们可以为item和index其别名
<view
wx:for="{{ ['Klaus', 'Alex', 'Steven'] }}"
wx:key="item"
wx:for-item="user"
wx:for-index="i"
>
{{ i }} --- {{ user }}
</view>
key
小程序在渲染的过程中,也使用了虚拟DOM,所以在小程序中进行遍历的时候,依旧需要加上key属性,其功能和vue和react中添加key属性的作用是一致的
当存在key属性后,小程序可以更好的识别对应的VDOM(key一致且节点类型一致的时候),此时在进行DIFF算法的时候,可以更好的识别新旧VNode
所以一句话,key的作用主要是为了高效的更新虚拟DOM
template
WXML提供**模板(template),**可以在模板中定义代码片段,在不同的地方调用
template标签主要用在小程序的早期版本中,因为小程序的早期版本并不支持组件化
<!--
如果一个template没有进行任何的使用,其本身是不会进行任何的渲染的
我们可以为其提供name属性 --- 为template设置一个名字
-->
<template name="userInfo">
<view>{{ userName }}</view>
<view>{{ userAge }}</view>
</template>
<!-- 使用
通过is属性进行模板的关联
通过data属性进行props传递 --- 注意: data是一个没有大括号的对象(★★★)
-->
<template is="userInfo" data="{{ userName: 'Klaus', userAge: 23 }}" />
引入
小程序wxml中提供了两种引入文件的方式: import和include
-
Import引入: import 可以在该文件中使用目标文件定义的 template ---- 先引入后使用
-
include: 可以将目标文件中除了
<template/> <wxs/>外的整个代码引入 --- 引入即使用
import
<template name="userInfo">
<view>{{ userName }}</view>
<view>{{ userAge }}</view>
</template>
<!--
可以使用import引入template模板
src --- 模板路径 --- 可以是相对路径或绝对路径 --- 后缀名wxml可以省略
-->
<import src="/wxml/template" />
<template is="userInfo" data="{{ userName: 'Klaus', userAge: 23 }}" />
include
<view>Klaus</view>
<view>23</view>
<!--
可以使用include来引入非wxs和template的代码片段 --- 功能类似于mixin
src --- 模板路径 --- 可以是相对路径或绝对路径 --- 后缀名wxml可以省略
-->
<include src="/wxml/foo" />
WXS
**WXS(WeiXin Script)**是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构
WXS 代码可以编写在 wxml 文件中的 <wxs> 标签内,或以 .wxs 为后缀名的文件内 --- WXS的两种使用方式
为什么要设计WXS语言呢?
- 在WXML中是不能直接调用Page/Component中定义的函数的
- 但是某些情况, 我们可以希望使用函数来处理WXML中的数据,这个时候就使用WXS
WXS使用的限制和特点
-
WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的API
--- 不可以直接调用JavaScript代码
-
WXS 函数不能作为组件的事件回调
----- 不可以作为事件响应函数使用
- 由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备 上二者运行效率无差异
<!--
在WXML的mustache语法中,不可以直接使用JavaScript语法,如果要使用必须结合WXS
-->
<view>{{ 12.6667.toFixed(3) }}</view>
页面内直接定义
<!-- module属性用来为wxs模块起名称 -->
<wxs module="format">
// 在WXS中不支持ES6的语法
var priceFormat = function(price, num) {
num = num || 2
price = parseFloat(price || 0)
return price.toFixed(num)
}
// WXS使用node环境作为沙盒执行环境 --- 所以导出方式必须使用CJS的模块导出方式
module.exports = {
priceFormat: priceFormat
}
</wxs>
<view>{{ format.priceFormat(16.66667, 2) }}</view>
外部引入
format.wxs
var priceFormat = function(price, num) {
num = num || 2
price = parseFloat(price || 0)
return price.toFixed(num)
}
module.exports = {
priceFormat: priceFormat
}
home.wxml
<!-- module属性用来为wxs模块起名称 -->
<wxs src="/wxs/format.wxs" module="format" />
<view>{{ format.priceFormat(16.66667, 2) }}</view>
事件
小程序需要经常和用户进行某种交互,比如点击界面上的某个按钮或者区域,比如滑动了某个区域, 这些交互都会产生各种各样的事件
<!-- 事件绑定的四个基本方式 -->
<view bindtap="handleTap">click me</view>
<view bind:tap="handleTap">click me</view>
<view catchtap="handleTap">click me</view>
<view catch:tap="handleTap">click me</view>
某些组件会有自己特性的**事件类型,**大家可以在使用组件时具体查看对应的文档
- 比如input有bindinput/bindblur/bindfocus等
- 比如scroll-view有bindscrolltowpper/bindscrolltolower等
但有些事件是所有组件都有的, 并且也比较常见的事件类型
touchcancel: 在某些特定场景下才会触发(比如来电打断等)
tap事件和longpress事件通常只会触发其中一个
<view
bind:touchstart="handleTouchStart"
bind:touchmove="handleTouchMove"
bind:touchend="handleTouchEnd"
bind:tap="handleTap"
bind:longpress="handleLongpress"
>
click me
</view>
Page({
handleTouchStart() {
console.log('handleTouchStart')
},
handleTouchMove() {
console.log('handleTouchMove')
},
handleTouchEnd() {
console.log('handleTouchEnd')
},
handleTap() {
console.log('handleTap')
},
handleLongpress() {
console.log('handleLongpress')
}
})
对于轻击事件,事件触发顺序为: touchstart -> touchend -> tap
对于长按事件,事件触发顺序为: touchstart -> longpress -> touchend
事件对象
当某个事件触发时, 会产生一个事件对象, 并且这个对象会被传入到对应事件的回调函数中
touches和changedTouches
touches --- 触发事件时候手指的个数组成的数组
changedTouches --- 触发事件的时候,相比之前,变化的手指个数
在绝大多数情况下,touches和changedTouches的值是一致的
但在以下情况下,这两个值有所差异:
- 在touchend中
- 在多手指触摸时
currentTarget和target
target --- 产生事件的那个dom元素
currentTarget --- 实际触发事件的那个dom元素
事件参数的传递
当视图层发生事件时,某些情况需要事件携带一些参数到执行的函数中, 这个时候就可以通过data-属性(HTML原生功能)来完成
- 格式: data-属性的名称
- 获取: e.currentTarget.dataset.属性的名称
<view bind:tap="handleTap" data-name="Klaus">
click me
</view>
Page({
handleTap(e) {
console.log(e.target.dataset.name)
}
})
事件冒泡和事件捕获
当界面产生一个事件时,事件分为了捕获阶段和冒泡阶段
在事件执行的时候,会先从外向内进行事件捕获,在从内往外进行事件冒泡
<!--
bind事件名 --- 对应事件在冒泡的时候被触发
capture-bind:事件名 --- 对应事件在捕获阶段被触发
注意: bind事件名和bind:事件名是等价的
但是capture-bind:事件名 必须存在冒号,也就是说capture-bin事件名 对应的事件回调是不会被正确触发的
-->
<view class="outer" bindtap="outerTap" capture-bind:tap="captureOuterTap">
<view class="inner" bindtap="innerTap" capture-bind:tap="captureInnerTap" />
</view>
Page({
outerTap() {
console.log('outerTap')
},
innerTap() {
console.log('innerTap')
},
captureOuterTap() {
console.log('captureOuterTap')
},
captureInnerTap() {
console.log('captureInnerTap')
}
})
阻止冒泡
在WXML中可以使用catch事件名来阻止事件传递
catch事件名和 catch:事件名 是等价的
<view class="outer" bindtap="outerTap" capture-bind:tap="captureOuterTap">
<!-- 使用catchtap来在冒泡阶段阻止事件冒泡 -->
<view class="inner" catchtap="innerTap" capture-bind:tap="captureInnerTap" />
</view>
<view class="outer" bindtap="outerTap" capture-bind:tap="captureOuterTap">
<!-- 使用capture-catch:tap来在捕获阶段阻止事件冒泡 -->
<view class="inner" bindtap="innerTap" capture-catch:tap="captureInnerTap" />
</view>