当前页面对某个选项进行切换,同步更新全局更新
该问题使用的技术栈是 React + Taro搭建的微信小程序
分析:
- 既然是全局更新就要在全局store中设置好存储的变量,方便统一管理
- 在首页将页面要获取的共同内容存到对应变量中
- 在对应的页面拿取这个变量的内容
- 然后就处理事件即可
遇到的问题:
- 写完代码后,查看页面没有变化,通过打印发现变量有更新,但是没有重新调用请求
解决方案
- 如果存在分页,检查数据顺序是否有问题
- 查看要调用的请求依赖哪些变量对象,查看这个对象中的变量或变量是否更新,是否每次更新时都更新该对象,如果没有,就要想办法赋值使该对象更新
- 如果是查看或者创建数据的时候用到
useQuery
来获取接口数据的话,且通过切换选项看到其他接口可以随着切换重新请求数据,而其中一个不行,问题极有可能是这个接口的useQuery
的使用了enabled:false
,导致数据不会重新更新,所以此时设置enabled:true
,或去掉enabled
都可解决 - 承接方法3,如果是创建和编辑在同一个页面在一起的话,初始数据和处理方式是有些不同的,这个时候,编辑页面需要
传参
表明它是编辑页面,编辑页面不需要切换,且要带着已经编辑过的数据,既useQuery
中要enabled:false
,记录数据,不轻易更新,所以解决方法是enabled: type !== 'edit'
,其中type时用来标记当前页面时编辑状态还是创建状态
缓存问题
该问题使用的技术栈是 React + Taro搭建的微信小程序
业务需求
- 判断用户是否第一次进入小程序,如果是第一次进入小程序,或者卸载了小程序后再次进入小程序,需要弹起一个窗来让用户选择和填写昵称和头像,而这时候已静默登录了
分析和解决方案
- 翻阅小程序文档可了解到
setStorageSync
,getStorageSync
这个操作 - 理清好业务逻辑
- 首先第一次进入时虽然静默登录了,但是
storage
并没有存储,所以可以在useEffect
中先调用wx.getStorageSync()
来获取我们要存储的key
,由于只需要获取第一次的情况,所以useEffect(()=> {}, [])
,这时候useEffect
不需要依赖,只调用一次就清除副作用 - 判断如果没有获取到对应的key就弹窗,有就不弹窗
- 在弹窗的取消、确认按钮和直接关闭弹窗的逻辑中调用
wx.setStorageSync('key', value)
这个方法存储,即可
- 翻阅小程序文档可了解到
注意事项
- 缓存只能存储字符串,所以如果要存储的值不是字符串类型的话,请用
JSON.stringify
将值序列化一下 - 最好设置
storage
时放在try{}catch(e){}
中方便捕获错误 - 按项目要求,点跳过拿的数据最好是直接拿到静默登录时服务器给的数据的信息,点确认则是要判断是否两个都有获取新数据,没有就禁用,有就存储。
- 不管拿到的数据是什么都要注意是否要更新该项目中的用户信息接口和store
1
2
3
4
5
6
7
8
9
10
11
12wx.setStorageSync('userInfo', JSON.stringify(e.detail.userInfo))
try {
wx.setStorageSync('headImg',value)
wx.setStorageSync('nickname',value)
} catch(e) {}
const headImgValue = wx.getStorageSync('headImg')
const nicknameValue = wx.getStorageSync('nickname')
if (headImagValue && nicknameValue) {
// 不弹窗
} else {
// 弹窗
}
- 缓存只能存储字符串,所以如果要存储的值不是字符串类型的话,请用
Taro 的消息机制 – 全局消息中心 evenCenter
eventCenter的使用场景一般用作于事件的传递,例如跨页面、跨组件做一些操作。
普通使用
- 使用
evenCenter.trigger(key)
来触发事件 - 使用
evenCenter.on(key,() => {})
来监听事件 - 在
useUnLoad
中要evenCenter.off(key)
卸载事件
- 使用
需要获取触发事件页面的数据给监听事件这边
- 使用
evenCenter.trigger(key, arg)
来触发事件 - 使用
evenCenter.on(key,() => {setArg(arg)})
来监听事件和触发当页的实时刷新 - 在
useUnLoad
中要evenCenter.off(key)
卸载事件
- 使用
发送数据给页面
- 使用
evenCenter.on(key,() => {fn(arg)})
来发送数据 - 使用
evenCenter.trigger(key, fn(arg))
来接收数据
- 使用
切换参数,然后返回
- 在
useUnload
中卸载的时候触发事件和传参 - 或在受影响的页面中从store中拿到全局变量xxx并且实时监听全局变量xxx的改变
- 在
Taro 页面跳转的消息机制 – eventChannel
使用方法
- A页面使用navigateTo等跳转方法直接触发事件res.eventChannel.emit(key,data)
- B页面首先需要获取当前页面的实例,然后调用getOpenerEventChannel()获取eventChannel对象
- B页面使用eventChannel.on(key,callbackFn)
- A页面也可以通过跳转时的events中的创建的事件来获取B页面传输过来的数据
- B页面通过eventChannel.emit(events中的事件名,data)来触发事件
示例
- A页面
1
2
3
4
5
6
7
8
9
10Taro.navigateTo({
url: "/pages/test/index", // 跳到页面B
events: {
acceptB: (data) {} // 获取B页面传送到当前页面的数据
},
success: (res) => {
// 向sendB发送数据
res.eventChannel.emit("sendB", {data: 要传递的数据})
}
}) - B页面
1
2
3
4
5
6
7
8
9const pages = Taro.getCurrentPages()
const current = pages[pages.length - 1]
const eventChannel = current.getOpenerEventChannel()
// 触发A页面events的事件
eventChannel.emit('acceptB', {要传给A的数据})
// 接受A页面对应事件传递的数据
eventChannel.on("sendB", (res) => {console.log(res)})
- A页面
相关文档
在 input 标签中使用 useState 和 useRef 的影响
该问题使用的技术栈是 React + Taro搭建的微信小程序
问题
- 问题1:使用
<Input value=""/>
标签,需要动态获取输入框中输入的value
的值来更新数据时,存在使用useState
来获取value
时,当value已有值
,要完全删除
旧值,输入新值时,删到旧值的最后一个字符
时输入框会一直循环重复
旧值,删不掉 - 问题2:当使用
useRef
获取的数据作为其他数据的依赖
时,对应的数据不会随着useRef
获取新数据的更新而更新
- 问题1:使用
分析存在的原因
useRef
直接操作dom
,返回的ref对象在组件的整个生命周期内保持不变,当更新时不会触发组件的重新渲染,而useState会存放组件中包含的各种数据(状态),并且当组件更新state`时会触发组件的重新渲染
解决方案
- 问题1:将变量的存储和获取方式从
useState
换成useRef
- 问题2:通过设置一个用
useState
存储的常量,当useRef
更新时,让常量更新,常量存储更新后的useRef
的数据,并作为其他数据的依赖,保证了useRef
的数据更新时其他数据也能随着更新。
- 问题1:将变量的存储和获取方式从
scroll-view 隐藏滚动条问题
该问题适用于任何使用小程序 scroll-view 组件或直接使用或二次封装等
- 根据小程序官方文档,
show-scrollbar
默认为true
即显示滚动条。 问题
- 当想要隐藏滚动条时,需要enhanced=”true”和show-scrollbar=”false”,但是实践会发现滚动条依然存在
存在的原因
- show-scrollbar=””,直接赋值时,因为字符串里面有值就是true
解决方法
- 根据不同框架,给
show-scrollbar
赋值为false
时,添加{}
,和enhanced
react
使用{false}
- 原生微信小程序 使用
"{{false}}"
- 根据不同框架,给
解决滚动禁止穿透页面
该问题适用于微信小程序
问题描述:
- 弹窗界面滚动(存不存在scroll-view无所谓,只要能滚动)带动下层的页面跟着滚动
解决方法:
- 1.在弹窗组件的插槽中用一个view包裹住该弹窗要展示的内容,然后给这个view添加catch:touchmove=”noop”
- 2.然后在ts/js文件中直接添加noop(){return}即可
复制大段文本,文本丢失问题
微信小程序的原生组件 textarea
单选框radio除了可以传value可以传其他的值
微信小程序的 radio-group 组件和 radio 组件,该问题收集于微信开放社区
问题
- data-传值在bindChange事件里接收不到,只能获取到value的值 === 向value传其他的值
解决方法
- 使用wxs处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/*wxml*/
<wxs module="JSON">
module.exports = {
stringify : function(item){
return JSON.stringify(item)
}
}
</wxs>
<radio-group ... >
....
<radio value="{{JSON.stringify(item)}}" checked="{{item.checked}}" />
</radio-group>
/*ts*/
radioChange: (e) => {
let d = JSON.parse(e.detail.value)
console.log('radio发生change事件,携带value值为:', d)
}
- 使用wxs处理
关于微信昵称中Emoji表情乱码问题
问题
- 昵称带Emoji表情,保存到数据库里,页面显示就乱码
解决方法
- 将包含该Emoji表情的信息encodeURIComponent编码,在使用的地方,在decodeURIComponent解码
- 在数据库连接的时候采用utf8mb4,数据库编码和表格编码以及对应的存储字段都采用utf8mb4编码
- 将包含该Emoji表情的信息encodeURIComponent编码,在使用的地方,在decodeURIComponent解码
小程序分享
该方法使用的时vue3 + taro
1 | <script setup> |
点击查看更多,展示更多数据
该方法使用微信小程序
分析和解决方案
- 先把框架写好
- 然后通过数据判断,是否超过一定数量total,和是否点击checked来判断展示更所数据的展示
- 然后通过服务端给的数据来展示
- 方案一:通过对应API的参数来控制点击前和点击后的数据,如点击前给两条,点击后给全部,这个要记得初始化checked,list和api对应参数
- 方案二:每次点击更多就加载2条数据甚至更多,checked要等到所有数据都加载完才为false,一般这样服务端给的数据应该是点击以下增加一页,给两条数据
服务端给的文本有回车换行 或者 空格等特殊字符
微信小程序
vant-checkbox-group 注意点
问题:
- 为什么点击没有勾选
解决方案:
- checkbox组下面的checkbox都要有name属性
- 使用checkbox组的方法,onChange,直接给checkbox组的value属性赋值,类型为字符串数组,值为:event.detail
switch用法
1 | switch(key){ |
Array.filter(Boolean)
本质上是将元素强制转换为布尔型并判断是否为false,以此来进行校验,适用于需要检验多个表单信息
移除数组中所有的”false”类型元素(false,null,undefined,0,NaN,空字符串)
- 得到的是过滤后的值数组
- 注意:不检验对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44eg:a simple explame
const a = [1,2,"b","",NaN,{},false, true,null,undefined,0]
const b = a.filter(Boolean)
eg: a advanced explame
// 定义要查找的关键字类型
type keyType = 'name' | 'age' | 'hobit' | 'remark' | 'position' | 'show'
// 定义当key为false类型时,提示的文本
const validateText: Record<keyType, string> = {
name: 'name is not empty!',
age: 'age is not zero!',
hobit: 'hobit is not empty!',
remark: 'remark is not empty!',
position: 'position is not empty!',
show: 'show is not false!',
}
// 定义一个对象
const InfoData: Record<keyType, string | number | boolean> = {
name: 'abc',
age: 12,
hobit: '打球',
remark: '备注',
position: '学生',
show: false
}
// 顶一个数组,用来存放要校验的key,按顺序校验
const keyInfo: keyType[] = [
'name',
'age',
'hobit',
'remark',
'position',
'show',
]
// 校验是否存在false类型,返回检验没有false类型的字段,并且返回不存在数组的第一个字段
const validate = keyInfo
.filter(Boolean)
.find((key: keyType) => !InfoData[key])
// 判断当返回的值不为undefined时,则提示对应的文本
if (validate) {
wx.showModal({
title: '提示',
content: validateText[validate],
})
}
编辑与查看为同一页时,处理方式(无缓存)
本次项目实战使用微信小程序 + ts
问题的描述:
- 第一次进入页面是编辑状态,保存了数据后,不管是否清除缓存,都展示最新的数据(只读)
- 只有在只读页面中点击对应的按钮,才能进入编辑状态页,并且编辑页只要没有按下保存按钮,则刷新后仍然回到点击前的只读页面,即接口返回的最新数据
- 只有当保存后,才会重新进入新的只读页
问题的解决:
- 首先需要将要编辑的数据及相关变量保存在同一个初始化函数中
- 之后通过接口返回的数据,如果失败,则为第一次进入预约页面的状态,标识编辑,然后初始化函数并且,设置变量来标识为编辑页
- 当内容编辑完成后,点击保存,进行校验,保存成功后,将变量标识为只读状态,并且调用接口获取最新的数据和状态,并存到初始化函数中的变量中,保持数据的统一性
- 当点击页面的按钮,调用初始化函数,并将变量设置为编辑状态,即可回到编辑页,
- 此时只有当在这个页面保存数据,才会产生新的页面,不然不管清缓存还是重新进入该页面,都应回到点击前的只读页面。
问题的总结:
- 此次遇到编辑和查看页面为同一页面时,要通过接口的数据返回,来判断并设置对应的标识以区分当前页是编辑还是查看状态
单个表单数据要存入一个对象
该问题使用微信小程序 + ts
问题的描述
- 当页面存在多个input标签,并需要保存提交
- 一般都会存储在同一个对象中,方便校验
- 校验使用上面的Array.filter(Boolean)里面有示例
问题的解决
- 多个input标签功能一致,则可以使用同一个函数来操作
- 至于具体存进那个key,则可以通过在wxml页面给每一个input添加mark:key=”定义的键”
- 然后每次调用函数时,可以获取key并存进对应的key中,或清除
问题的总结
- 当存在多个标签一致时,观察功能/样式是否相同,然后通过给一个区分的标签来实现调用同一个函数实现不同的功能,以减少代码量
setData第二参数
微信小程序中setData方法用于设置数据,更改数据
参数
- 第一个参数:Object data, 必传, 代表这次要改变的数据
- 第二个参数:Function callback, 选填, 代表setData引起的界面更新渲染完毕后的回调函数
浅薄理解:
- 参数一就是主要用来更新数据,设置数据,参数二则是延时器的作用,渲染完在调用回调函数
示例:
- 第一个参数:this.setData({val,b:a})
- 第二个参数:this.setData({val}, () => { this.setData(value)})
picker-view的value赋值问题
picker-view时微信小程序的原生组件,用于自定义picker
- 已知picker-view的value属性值为每一个picker-view-column默认选中的索引数组,存在有多少个picker-view-column,数组长度就为多少
问题:
- 给value赋值时,不管是不是第一项没成功赋值,定位到对应的索引,还是其他项,都显示为在索引0的位置和索引0的值,与所求相异
原因:
- 初始化函数时没有成功赋值进去,存在延时
解决:
- 建议用setData的第二参数赋值,this.setData({val}, () => { this.setData(value)})
多行文本溢出省略号
- 核心代码
1
2
3
4
5
6overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 6;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical; - 注意:如果无效可以限制宽高
- 单行文本溢出省略:只要前两行
跳转返回上一页面并传递参数
微信小程序
方法一: 使用
wx.navigateBack
- 1.在子页面中首先获取上一页面
- const pages = getCurrentPages()
- const prePages = pages[pages.length -2] //上一级页面
- 2.调用上一页面的setData方法,将数据存到上一页面,存储的变量要现在上一页面的data中声明
- prePages.setData({存储的变量:这个页面要存储的值})
- 3.返回上一页面
- wx.navigateBack({ delta: 1 })
- 4.上一页面接收子页面的参数可在onLoad或onShow中执行,onShow每次页面加载都会执行,并保存
- const pages = getCurrentPages()
- const currentPages = pages[pages.length-1]
- this.setData({存储的变量:这个页面要存储的值})
- 1.在子页面中首先获取上一页面
方法二:使用
wx.navigateTo
- 1.子页面通过路径传递参数
- wx.navigateTo({ url:
/xxx/xxx/xxx?params=${params}¶ms1=${params}
})
- wx.navigateTo({ url:
- 2.父页面通过onLoad(options)方法获取参数
- onLoad(options){ const params = options.params }
- 1.子页面通过路径传递参数
如何避免输入中文拼音时触发input事件
原生html+js
- 监听compositionstart 、 compositionend
- 定义isComposite 为false,在start中设置为true,在end中设置为false
- 然后在input事件中判断,当isComposite为false时就进行输入搜索事件
- 之后在end事件中在调用输入搜索事件
实现防纂改的水印
- react框架使用ant design,有一个watermark组件
一个布局存在多个点击事件,先后触发问题
本质:微信小程序 bindtap 和 catchtap 的区别
- 事件冒泡:
- bindtap会将事件传递给父节点进行处理,而catchtap会阻止事件继续冒泡到父节点。
- 即
当一个元素上的bindtap事件被触发,如果该元素的父节点又有bindtap事件,则父节点的事件也会执行;而catchtap则只会触发当前元素的事件处理函数
- 绑定顺序:
- bindtap的触发顺序是由子元素向父元素冒泡的顺序(由内向外)
- catchtap的触发顺序是由父元素向子元素铺捕获的顺序(由外到内)
- 阻止默认:
- bindtap可以通过返回false来阻止默认行为的触发,而catchtap无法阻止
- 通常情况下使用bindtap,不想触发父元素使用catchtap
小红点单数圆形,双数圆矩形
参考vant-icon
1 | .dot { |