微信小程序常见知识点
- 1、对微信小程序的理解
- 2、小程序中wxss和css的异同
- 3、小程序中的模板语法WXML(标签、数据、渲染)
- 1. 标签的使用
- 2. 数据绑定
- 3. 数据渲染
- 4. 逻辑渲染
- 5. 列表渲染
- 6. template(模板)
- 7. 引用
- 4、小程序中的生命周期函数有哪些?(APP、Page、Component)
- 1. APP的生命周期
- 2. Page的生命周期
- 3. Component的生命周期
- 5、小程序中事件定义与传参
- 1. 事件定义:
- 2. 事件传参
- 6、小程序中常见的界面跳转的方式,以及区别?
- 7、小程序中如何修改data上的数据?
- 8、小程序中如何进行本地存储?
- 9、小程序中界面跳转如何传递参数?如何获取这些参数?
- 10、小程序中如何进行父子组件传参?
- 11、对Behaviors的理解
- 12、谈谈你关于组件封装的心得
- 理解:
- 优点:
- 13、怎么封装小程序的数据请求
- 14、如何提高小程序的加载速度?
- 15、微信小程序常见的开放能力API有哪些?
- 16、对WebSocket的理解
- 17、瀑布流的实现
1、对微信小程序的理解
小程序是一种开放能力,开发者可以快速地开发一个小程序。小程序可以在微信内被便捷的获取和传播,同时具有出色的使用体验。
微信小程序的优势:
微信助理,容易推广。
小程序拥有众多入口,这些入口有助于企业更好的获取流量,从而进行转化、变现。使用便捷。
用户在使用小程序时,只需要轻轻点一下就可以使用,更加符合用户对使用方便、快捷的需求,所以小程序的用户数量不断增加。体验良好,有接近原生app的体验。
。在微信生态里,小程序在功能和体验上是可以秒杀掉 H5 页面的,H5 页面经常出现卡顿、延时、加载慢、权限不足等原因,而这些问题在小程序里都不会出现。成本更低。
从开发成本到运营推广成本,小程序的花费仅为APP的十分之一,无论是对创业者还是传统商家来说都是一大优势。
微信小程序的劣势:
单个包大小限制为2M,
这导致无法开发大型的应用,采用分包最大是20M(这个值一直在变化,以官网为准)。需要像app一样审核上架,
这点相对于H5的发布要麻烦一些。处处受微信限制。
例如不能直接分享到朋友圈,涉及到积分,或者虚拟交易的时候,小程序也是不允许的。
2、小程序中wxss和css的异同
WXSS和CSS类似,不过在CSS的基础上做了一些补充和修改
- 尺寸单位 rpx:rpx是响应式像素,可以根据屏幕宽度进行自适应。规定屏幕宽度为750rpx。在不同的手机型号下1rpx=屏幕宽度/750。(phone6下1rpx = 0.5px)
- 样式导入import:可以@import来导入其他的wxss
- 样式选择器:类选择器、id选择器、元素选择器、伪元素选择器
@import './test_0.wxss'
3、小程序中的模板语法WXML(标签、数据、渲染)
1. 标签的使用
在小程序中没有H5提供的那些标签了,这里我们需要使用小程序给我们提供的组件。常用的标签有
- view:相当于div;
- text:相当于span;
- image:相当于img
2. 数据绑定
- 数据定义:
- 引用数据:通过{{}}的方式可以引用数据。
小程序中任何需要获取数据的地方都需要用{{}},包括标签内的属性。
data:{
return {
msg:"hello world",
num: 18,
}
}
3. 数据渲染
- 渲染层和数据相关。
- 逻辑层负责产生、处理数据。
- 逻辑层通过 Page 实例的 setData 方法传递数据到渲染层。
<view>{{ msg }}</view>
Page({
data:{
return {
msg:"hello world",
num: 18,
}
}
onLoad: function () {
this.setData({ msg: 'Hello World2222' })
}
})
4. 逻辑渲染
wx:if和hidden
- wx:if:WXML 中,使用 wx:if=“{{condition}}” 来判断是否需要渲染该代码块
如果要一次性判断多个组件标签,可以使用一个 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。- hidden:通过hidden属性也可以进行条件渲染。
- wx:if和hidden的异同:
同:都能控制元素的显示与隐藏
异:wx:if在不满足条件的时候会删除掉对应的DOM,hidden属性则是通过display属性设置为none来进行条件渲染。
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
<view hidden="{{condition}}">
隐藏
</view>
5. 列表渲染
wx:for :在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。
wx:for-index, wx:for-item 用来指定index和item的别名wx:key:指定列表中项目的唯一的标识符。
要求:需要是列表中唯一的字符串或数字;保留关键字 this: 代表在 for 循环中的 item 本身,并且item本身是唯一的字符串或者数字
作用:能提高重排效率
<!-- array 是一个数组 -->
<view wx:for="{{index in array}}" wx:key="{{index}}">
{{index}}: {{item.name}}
</view>
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.name}}
</view>
对应的脚本文件:
Page({
data: {
array: [{
name: '天亮教育',
}, {
name: '尚云科技'
}]
}
})
6. template(模板)
WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。使用 name 属性,作为模板的名字。然后在 内定义代码片段。
使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入。
定义
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
调用
<!-- msgList:[
{
index: 0,
msg: '这是一段模板',
time: '2020-10-10'
}
] -->
<view wx:for="{{msgList}}">
<template is="msgItem" data="{{...item}}"></template>
</view>
7. 引用
WXML 提供两种文件引用方式import和include。
- import:可以在该文件中使用目标文件定义的 template
需要注意的是 import 有作用域的概念,即只会 import 目标文件中定义的 template,而不会 import 目标文件中 import 的 template,简言之就是 import 不具有递归的特性。
在 item.wxml 中定义了一个叫 item的 template :
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
在 index.wxml 中引用了 item.wxml,就可以使用 item模板:
<import src="item.wxml"/>
<template is="item" data="{{text: '测试'}}"/>
- 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>
4、小程序中的生命周期函数有哪些?(APP、Page、Component)
1. APP的生命周期
- onLaunch()
小程序初始化完成时触发,全局只触发一次。参数也可以使用wx.getLaunchOptionsSync 获取。
一般在这个生命周期函数中执行 全局数据 的初始化操作。- onShow()
小程序启动,或从后台进入前台显示时触发,可以触发多次。
也可以使用 wx.onAppShow 绑定监听。- onHide()
小程序从前台进入后台时触发,可以触发多次。也可以使用 wx.onAppHide 绑定监听。
/*当小程序初始化时,触发(全局只触发一次)*/
onLaunch: function () {},
/*当小程序启动,或从后台进入前台显示时触发*/
onShow:function(options){},
/*当小程序从前台进入后台时触发*/
onHide:function(){}
2. Page的生命周期
打开页面的加载顺序:onLoad,onShow,onReady
切换页面时只会加载onShow,onHide
- onLoad(options)
页面加载时触发。只触发一次,可以在 options中获取到界面跳转的参数。
一般在这个生命周期函数中执行当前页面中的data的初始化操作和判断所需的全局状态(如用户登录状态)等。- onShow()
页面显示时触发,可触发多次。- onReady()
页面初次渲染完成时触发。只触发一次,代表页面已经准备妥当,可以和视图层进行交互。
注意:对界面内容进行设置的 API 如 wx.setNavigationBarTitle,请在onReady之后进行。
- onHide()
页面隐藏时触发。 如 wx.navigateTo 或底部 tab 切换到其他页面,小程序切入后台等,可触发多次。- onUnload()
页面卸载时触发。如 wx.redirectTo 或 wx.navigateBack 到其他页面时。 一般在这个生命周期函数中执行清除定时器、closeSocket等操作。
/* 监听页面加载*/
onLoad: function (options) {},
/*监听页面初次渲染完成*/
onReady: function () {},
/*监听页面显示*/
onShow: function () {},
/*监听页面隐藏*/
onHide: function () {},
/*监听页面卸载*/
onUnload: function () {},
3. Component的生命周期
微信小程序的组件中的生命周期函数有以下六种,其中最重要的是 created、attached、detached
- created:创建
- attached :在页面打开
- detached:在页面移除
- created()
组件实例刚刚被创建好时, created 生命周期被触发,此时还不能调用 setData。
通常情况下,这个生命周期只应该用于给组件添加一些自定义属性字段。- attached()
在组件完全初始化完毕、进入页面节点树后, attached 生命周期被触发。此时, this.data已被初始化为组件的当前值。
这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。- detached()
在组件离开页面节点树后, detached 生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached 会被触发。(页面节点树即组成页面的所有元素的集合。)
Component({
/*生命周期函数*/
lifetimes: {
created:function(){
//组件被创建时执行
},
attached: function () {
// 在组件实例进入页面节点树时执行
},
detached: function () {
// 在组件实例被从页面节点树移除时执行
},
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
created: function () {
//组件被创建
},
attached: function () {
// 在组件实例进入页面节点树时执行
},
detached: function () {
// 在组件实例被从页面节点树移除时执行
},
})
5、小程序中事件定义与传参
1. 事件定义:
- bind:加自定义事件,如:bind:tap=“执行函数”
在小程序中绑定事件可以以bind开头然后跟上事件的类型,如bindtap绑定一个点击事件,对应的值是一个字符串,需要在page构造器中定义同名函数,每次触发事件之后就会执行对应函数的内容。- catch:阻止事件冒泡
- capture-bind:事件捕获
2. 事件传参
事件传参:data-加自定义=‘自定义‘ 。 参数在在自定义事件中的参数e中获取
参数e中target和currentTarget的区别:currentTarget为当前事件所绑定的组件,而target则是触发该事件的源头组件。
<view bindtap="handleTap">点击事件</view>
<view catch:tap="handleTap">另一种写法</view>
<view capture-bind:tap="handleTap">另一种写法</view>
<!-- data-参数名=’参数值’ -->
<view bindtap="handleTap" data-msg="我是事件的参数">点击事件</view>
// pages/my/index.js
Page({
handleTap(){
console.log("执行了点击事件");
// 通过currentTarget中的dataset属性可以获取时间参数
console.log(e.currentTarget.dataset.msg);
}
})
6、小程序中常见的界面跳转的方式,以及区别?
方式 | 区别 |
---|---|
<navigator > | open-type属性决定跳转方式 |
wx.navigateTo | 保留当前页面,只能打开非 tabBar 页面。 |
wx.redirectTo | 关闭卸载当前页面,只能打开非 tabBar 页面。 |
wx.switchTab | 关闭所有非tabbar页面, 只能打开 tabBar 页面。 |
wx.reLaunch | 关闭卸载所有页面,可以打开任意页面。 |
wx.navigateBack | 返回前面的页面,可以指定返回多少页,如果用过redirectTo,那么被关 |
<navigator url=”页面地址” target=“self” open-type=“reLaunch”><navigator>
wx.navigateTo({
url: 'test?id=1',
})
wx.redirectTo({
url: 'test?id=1'
})
wx.switchTab({
url: '/index'
})
wx.reLaunch({
url: 'test?id=1'
})
wx.navigateBack({
delta: 2 //返回的页面数,如果 delta 大于现有页面数,则返回到首页。
})
7、小程序中如何修改data上的数据?
在js文件中,this.data.变量修改,只可以修改逻辑层的数据,渲染层不会改变
用app实例的this.setData()方法修改data数据逻辑层和渲染层的数据都会更新
8、小程序中如何进行本地存储?
1. 异步:
异步存储:wx.setStorage({
key:“key”,
data:‘value’
})
异步获取:wx.getStorage({‘key’})2. 同步:
同步存储:wx.setStorageSync(‘key’,‘data’)
同步获取:wx.gettStorageSync(‘key’)
9、小程序中界面跳转如何传递参数?如何获取这些参数?
传参分为声明式和函数式
注意:wx.switchTab和wx.navigateBack不能传递参数
获取参数:通过跳转界面onLoad方法的options参数可以获取到路由传参
声明式:
<navigator url='url?id=1'></navigator>
<navigator url='url?id={{变量名}}'></navigator>
函数式:
toPath(){
wx.navigateTo({
url:'url?id=123',
})
}
toPath(){
wx.navigateTo({
url:'url?id={{变量名}}',
})
}
10、小程序中如何进行父子组件传参?
父传子:
在父页面中:
<son msg=’hello’></son>
<son></son>
子组件接收:
properties:{
msg:{
type:[String,Number],
value:’hello world’,
}
}
子组件:
<view>{{msg}}</view>
打印结果:
hello
hello world
子传父:
父页面:
<son bind:fromson=’fromson’></son>
子组件:
<button bindtap=’tofather’>子传父</button>
子组件中触发:
methods:{
tofather(){
this.triggerEvent(‘fromson’,’111’)
}
}
父组件接收子组件参数:
fromson(res){
console.log(res.detail)
this.setData({
“fromson”:res.detail
})
}
11、对Behaviors的理解
- Behaviors是用于组件间代码共享的特性,类似于 “mixins”。
- behavior 可以包含一组属性、数据、生命周期函数和方法
属性:myBehaviorProperty
数据字段:myBehaviorData
方法:myBehaviorMethod
生命周期函数:attached、created、ready
//注册一个 behavior,接受一个 Object 类型的参数
// 组件中的参数一样
module.exports = Behavior({
data:{
Behavior:"Behavior",
msg:"behavior",
obj:{
msg:"behavior"
}
},
created(){
console.log('created-Behavior');
},
})
// 在son中用Behavior
//son.js
import Behavior from "../../behaviors/behavior"
Component({
// 用Behavior
behaviors:[Behavior],
// 组件的属性或方法会覆盖 behavior 中的同名属性或方法;
data: {
// 有同名的数据字段,对象类型,会进行对象合并,其他会覆盖
msg:"son",
obj:{
id:2,
msg:'son'
}
},
// 组件和Behavior的生命周期不会覆盖,会合并
created(){
console.log('created-son');
},
12、谈谈你关于组件封装的心得
理解:
在开发项目的过程中经常遇到有些界面的UI元素是可以复用的,这个时候可以考虑把这些UI元素抽象成组件
在开发过程中也会发现有些界面比较复杂,写起来比较麻烦,而且,单个文件的代码量过多也不利于后期维护,这是就可以按照功能拆分之前的界面元素,每个组件单独维护这个组件的功能,将复杂的问题拆解成一个个小问题,提高了代码的可维护性。
优点:
高内聚低耦合;
避免了代码间的冲突;
容易维护;
提高开发效率,
方便重复利用,
提高可维护性;
13、怎么封装小程序的数据请求
小程序接口请求:wx.request
不会跨域,因为不是浏览器,没有同源策略
封装请求
function request(options) {
// 请求拦截器
// ...
// 加一些统一的参数,或者配置
if (!options.url.startsWith("https://") &&!options.url.startsWith("http://")) {
options.url = "https://showme2.myhope365" + options.url
}
// 默认的请求头
let header = {
"cookie": wx.getStorageSync("cookie") || "",
"content-type": "application/x-www-form-urlencoded",
};
if (options.header) {
header = {
...header,
...options.header
}
}
return new Promise((reslove, reject) => {
// 调用接口
wx.request({
// 默认的配置
// 加载传入的配置
...options,
header,
success(res) {
// 响应拦截器,所有接口获取数据之前,都会先执行这里
// 1. 统一的错误处理
if (res.statusCode != 200) {
wx.showToast({
title: '服务器异常,请联系管理员',
})
}
reslove(res)
},
fail(err) {
reject(err)
}
})
})
}
//封装get请求
export function get(url, options = {}) {
return request({
url,
...options
})
}
//封装post请求
export function post(url, data, options = {}) {
return request({
url,
data,
method: "POST",
...options
})
}
14、如何提高小程序的加载速度?
1、控制代码包的大小: (1)代码包的体积压缩可以通过勾选开发者工具中“上传代码时,压缩代码”选项(2)及时清理无用的代码和资源文件(3)减少资源包中的图片等资源的数量和大小
2、分包加载,预加载: 将用户访问率高的页面放在主包里,将访问率低的页面放入子包里,按需加载;采用子包预加载技术,并不需要等到用户点击到子包页面后在下载子包
3、预请求: 请求可以在页面onLoad就加载,不需要等页面ready后在异步请求数据;尽量减少不必要的https请求,可使用 getStorageSync() 及 setStorageSync() 方法将数据存储在本地
4、避免不当的使用setData:
不要过于频繁调用setData,应考虑将多次setData合并成一次setData调用 5、使用自定义组件:
对于一些独立的模块我们尽可能抽离出来,这是因为自定义组件的更新并不会影响页面上其他元素的更新;各个组件也将具有各自独立的逻辑空间。每个组件都分别拥有自己的独立的数据、setData调用
15、微信小程序常见的开放能力API有哪些?
API | 作用 |
---|---|
wx.getNetworkType({}) | 检查网络类型,例如:wifi,5g,4g,3g,2g等 |
wx.downloadFile({}) | 从网络上下载文档 |
wx.scanCode({}) | 扫一扫 |
wx.canIUse() | 判断小程序的API,回调,参数,组件等是否在当前版本可用。返回值为布尔类型。 |
wx.getUserProfile | 获取用户信息。每次请求都会弹出授权窗口,用户同意后返回 userInfo。 |
wx.getUserInfo | 获取用户信息。//已经停止使用 |
16、对WebSocket的理解
最典型的例子:聊天室
由于http只能是单向发起的,只能由客户端主动发起,服务端被动响应。服务端无法主动向客户端发送消息,如果想实现类似于聊天室这种即时通讯的功能,就需要使用消息轮询。轮询的效率低,比较消耗资源。
WebSocket最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
而WebSocket协议具有以下特点:(可以更好的实现即时通讯)
1、 webSocket是一种在单个TCP连接上进行全双工通信的协议
2、websocket建立连接时,数据是通过http传输的,建立连接后就不需要http协议了。
3、websocket建立连接后就是全双工模式,也是基于tcp协议。
4、建立连接之后,不必在客户端发送request之后服务器才能返回信息到浏览器,这时候服务器有主动权,允许可以随时发消息给客户端
5、发送的信息中不必带有head部分信息了,相对于http来说,降低了服务器的压力,极大的减少了不必要的网络流量与延迟。
6、没有同源限制,客户端可以与任意服务器通信
7、协议标识符是ws(如果加密,则为wss),服务器网址就是 URL
17、瀑布流的实现
将数组拆分成左右两个数组
记录左右数组的高度,遍历总数组,将新的元素放在高度比较小的数组里
//wxml文件
<template name="postList">
<view class="box" bindtap="toChat" data-postid="{{item.postsId}}">
<view class="title">
{{item.title}}
</view>
<view class="imgBox">
<image src="{{item.coverImgUrl}}" mode="widthFix"></image>
</view>
</view>
</template>
<view class="bigBox">
<view class="leftBox">
<template is="postList" data="{{item}}" wx:for="{{leftList}}" wx:key="postsId"> </template>
</view>
<view class="leftBox">
<template is="postList" data="{{item}}" wx:for="{{rightList}}" wx:key="postsId"></template>
</view>
</view>
<view class="load">
<van-loading type="spinner" wx:if="{{isLoading}}" />
</view>
<view wx:if="{{isEnd}}" class="tip">没有更多了...</view>
<view class="back" hidden="{{backShow}}" bindtap="backTap" >
<van-icon name="back-top" />
</view>
//js文件
import { getlist } from "../../api/chat"
// pages/chat/chat.js
Page({
/**
* 页面的初始数据
*/
data: {
list:[],
leftList:[],
rightList:[],
leftHeight:0,
rightHeight:0,
// 整个数据处理完成
finish:false,
pageNum:1,
pageSize:10,
total:0,
isEnd:false,
isLoading:true,
// 返回顶部
backShow:true,
},
// 请求的函数封装
getPost(){
getlist(this.data.pageNum,this.data.pageSize).then(res=>{
if(res.data.code == 0){
wx.stopPullDownRefresh();
this.initList(res.data.rows);
this.data.total = res.data.total;
}
})
},
// 处理数据的封装
initList(list){
this.data.finish = false
if(list.length == 0){
this.data.finish = true;
// 没数据了
return
}
let item = list.shift();
// 获取图片信息
wx.getImageInfo({
src:item.coverImgUrl,
success:(res)=>{
if(this.data.leftHeight <= this.data.rightHeight){
// 加到左列表
this.data.leftList.push(item);
this.data.leftHeight += res.height / res.width
}else{
this.data.rightList.push(item);
this.data.rightHeight += res.height / res.width
}
// 更改视图
this.setData({
leftList:this.data.leftList,
rightList:this.data.rightList,
isLoading:false
})
},
complete:()=>{
this.initList(list);
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.setData({
isLoading:true
})
// 处理数据
this.getPost();
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
this.setData({
isEnd:false
})
// 下拉刷新
if(this.data.finish){
this.data.pageNum = 1
this.setData({
leftList:[],
rightList:[],
leftHeight:0,
rightHeight:0
})
this.getPost();
}else{
return
}
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
this.setData({
isLoading:true,
})
// 触底了
if(this.data.finish){
if(this.data.pageNum * this.data.pageSize >= this.data.total){
this.setData({
isEnd:true,
isLoading:false,
})
}else{
this.data.pageNum ++;
this.getPost()
}
}
},
})
更多推荐
微信小程序常见知识点
发布评论