总结记录我在开发微信小程序项目过程中,在前端开发过程中总结的经验和知识点
文章目录
- 实现顶部菜单:可横向滚动,且右边渐隐
- 加载圆圈(会动态旋转)
- 限制只能输入数字
- 去除点击阴影
- 阻止事件冒泡和阻止默认行为
- 自定义渐入渐出动画
- js的.map用法
- 异步操作
- scroll-view标签
- overflow
- image标签
- wxml传参给js
- 图片预览js逻辑
- 不同页面之间跳转传参
- 抽屉弹窗
- 圆角属性
- new promise 函数
- 获取用户头像与昵称
- 自定义组件
- 父组件向子组件传值
- 子组件向父组件传值
- wx.createSelectorQuery()方法
- 记录开发过程中遇到的一个de了很久的bug
- 在微信小程序中使用vantUI
- 想在文字中加空格
- 官方picker选择器(包括官方提供的省市区选择器)
- 列表左滑右滑删除:
- 页面之间传递参数
- 实现网格排列的技巧
- view实现网格排列
实现顶部菜单:可横向滚动,且右边渐隐
效果图:可以看出右边的字渐渐隐藏了
右边渐隐用mask,但是微信小程序要改成-webkit-mask-box-image,mask我试了下是无效的
所以右边渐隐的关键代码是:
-webkit-mask-box-image: linear-gradient(90deg, #000000 90%, transparent);
可以通过调整百分数来调整mask的覆盖宽度,自己该参数看看效果就知道了
还有很关键的一点,这个mask加在哪个css上?答案是:以我下面写的3层为准,要在最外面一层添加,我试了下添加在swtich-wrap中间层是不行的
参考:
小技巧 | 渐变消失遮罩的多种实现方式
mask-image属性小程序失效
我自己的文章
完整代码如下:
<view class="switch">
<view class="switch-wrap">
<view wx:for="{{store}}" wx:key="index" class="{{tabValue === item.value ? 'choose' : 'nochoose'}} switch-item" data-id="{{item.value}}" bindtap="onChange">{{ item.label }}</view>
</view>
</view>
.switch {
white-space: nowrap;
overflow: auto;
width: 65%;
-webkit-mask-box-image: linear-gradient(90deg, #000000 90%, transparent);
}
.switch-wrap{
display: inline-flex; /* 一定要inline-flex */
position: relative;
}
.switch-item {
width: 112rpx;
height: 56rpx;
margin-right: 0rpx;
/* position: relative; */
display: flex;
justify-content: center;
align-items: center;
font-size: 28rpx;
}
/*
.switch-item:last-of-type {
margin-right: 0;
} */
.choose {
background-color: #F6F7F9;
border-radius: 200rpx;
color: #272B3D;
font-size: 28rpx;
font-weight: 600;
}
.nochoose {
color: #BEBEBE;
font-size: 28rpx;
font-weight: 400;
}
加载圆圈(会动态旋转)
<view wx:if="{{!isEnd}}" class="more-load-bx">
<view class="loading" />
</view>
/* 底部更多加载 */
.more-load-bx {
width: 100%;
height: 50rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.more-load-bx .loading {
position: relative;
width: 40rpx;
height: 40rpx;
border: 8rpx solid #F8BF4E;
border-top-color: rgba(248, 191, 78, 0.1);
border-right-color: rgba(248, 191, 78, 0.1);
border-bottom-color: rgba(248, 191, 78, 0.1);
border-radius: 100%;
animation: circle infinite 0.75s linear;
}
@keyframes circle {
0% {
transform: rotate(0);
}
35% {
transform: rotate(180deg);
}
70% {
transform: rotate(320deg);
}
100% {
transform: rotate(360deg);
}
}
限制只能输入数字
参考我自己写的文章
去除点击阴影
navigator标签点击会有阴影,去除方法:
全局页面去除(推荐,一键到位,所有页面的都会去除):
在全局的css里加上下面的内容即可去除
.navigator-hover {
background-color: transparent !important;
opacity: 1;
}
局部页面去除:
在页面的标签里加上hover-class="none"
<navigator url="/pages/test" hover-class="none">
</navigator>
阻止事件冒泡和阻止默认行为
我自己写的文章:阻止事件冒泡和阻止默认行为
自定义渐入渐出动画
如抽屉的渐入渐出:
transition: height 0.3s
秒数可以自己定
js的.map用法
异步操作
我自己的文章:JavaScript异步操作
scroll-view标签
设置height
:即scroll的长度,如height为100vh,则长度为整个可视区域,有时需要动态计算,此时就可以用到本文后面的wx.createSelectorQuery()函数部分的内容
设置横向还是竖向滚动
:scroll-x=“true” / scroll-y=“true”
设置滚动到底部触发函数
:bindscrolltolower=" ",常用于分页查询,滚动到底部,触发向后端再次获取分页数据展示
设置下拉刷新:
- refresher-enabled=“true”:开启自定义下拉刷新
- refresher-triggered=“{{trigger}}”:设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发
- bindrefresherrefresh=“”:自定义下拉刷新触发的函数
官方文档:官方文档
overflow
overflow设置有两种值,一个是hidden,一个是scroll
hidden
表示超出可视区域则隐藏
scroll
表示超出可视区域则可滚动展示
不设置overflow则默认是overflow: auto(此时超出则scroll)
image标签
图片加载时闪一下再显示的bug,是因为没有设置图片高度,参考:
参考
图片mode可以是:
mode="aspectToFit"
:缩放模式,保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来
mode="aspectToFill"
:缩放模式,保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。
mode="scaleToFill"
:缩放模式,不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素
mode="widthFix"
:宽度不变,高度自动变化,保持原图宽高比不变,**再设置想要展示的图片宽度(如UI设计图中给定的宽度,就可以按照UI设计图大小展示图片)**即可
资料:image组件的4种缩放模式与9种裁剪模式, 和静态多文章列表
wxml传参给js
图片预览js逻辑
可能需要结合 wxml传参给js
官方文档:图片预览官方文档
例如:
不同页面之间跳转传参
参考:页面跳转
抽屉弹窗
分为两个部分:
- mask
- 抽屉本身
动画设置使用官方函数 wx.createAnimation
抽屉动画
每个选项之间的分割线
参考:
圆角属性
new promise 函数
参考:new promise
资料
获取用户头像与昵称
自定义组件
参考:
例子:
Component({
/**
* 组件的属性列表
*/
properties: {
listData: {
type: Object,
value: [],
},
otherProperty: {
type: String,
value: '',
}
},
// 监听每个属性值的变化
observers: {
'listData': function(newVal) {
// 处理 listData 属性的变化
console.log('listData 的新值:', newVal);
},
'otherProperty': function(newVal) {
// 处理 otherProperty 属性的变化
console.log('otherProperty 的新值:', newVal);
},
// 可以继续添加其他属性的观察者函数
},
// 其他组件的生命周期函数和方法
});
更具体的示例:
// 从外部传进组件的值
properties: {
listData: {
type: Object,
value: [],
}
},
// 观察者函数,监听properties中属性值的变化
observers: {
'listData': function(newVal){
if(newVal.length>0 && this.data.goods!==newVal){
this.setData({
goods: newVal
})
// console.log("Listen data from index");
}
}
},
/**
* 组件的初始数据
*/
data: {
goods:[]
},
/**
* 组件的方法列表
*/
methods: {
onChange: function (e) {
this.triggerEvent('change', e.currentTarget.dataset.id)
},
}
父组件向子组件传值
子组件向父组件传值
this.triggerEvent('myevent', myEventDetail, myEventOption)方法
其中参数:
myevent为方法名,
myEventDetail是传到组件外的数据,
myEventOption为是否冒泡的选项,有三个参数可以设置:
bubbles:默认false 事件是否冒泡
composed:默认false 事件是否可以穿越组件边界
capturePhase:默认false 事件是否拥有捕获阶段
大概步骤是:
- 子组件js中写传值的函数
- 父组件js中写对传入的值进行相应处理的函数
- 父组件的wxml相应调用子组件的地方进行bind绑定,格式
bind:<子组件传值的函数>=“<父组件处理传入的值的函数>”
示例:
// child.js
// 子组件js中写传值的函数
methods: {
changeName() {
this.triggerEvent('changeName', {
name: '李四'
})
}
}
// parent.js
// 父组件js中写对传入的值进行相应处理的函数
handelChangeName(event) {
console.log(event)
// { name: '李四' }
}
<!-- parent.wxml -->
<!-- 父组件的wxml相应调用子组件的地方进行bind绑定 -->
<child bind:changeName="handelChangeName" />
wx.createSelectorQuery()方法
注意:在自定义组件或包含自定义组件的页面中,应使用this.createSelectorQuery()
获得某个元素的内容区域上/下边界相对于可视区域(即视窗)顶部的距离
在小程序的wx.createSelectorQuery()
方法中,使用 boundingClientRect()
方法查询元素的位置信息时,可以获取到的 res 对象中包含了一些属性,其中包括 top 属性
(从元素的内容区域顶部开始到可视区域顶部的距离,下面的bottom同理)。
明确两个概念:
元素的内容区域
元素的内容区域是指元素内部实际承载内容的部分,不包括边框(border)、内边距(padding)和外边距(margin)。
可视区域
可视区域是指你可以看得到的页面的区域,所以可视区域顶部就是你现在能看到的页面区域的顶部,区别于页面的顶部。
这对于不会滚动的页面来说可能不好理解,要结合页面滚动来区别。如果一个页面滚动,那么可视区域顶部是现在你能看到的区域的顶部,而页面的顶部是指你页面最开始还没滚动时的那个顶部,所以还需要包括你页面滚动的距离。
wx.getSystemInfoSync().windowHeight;
获得的就是可视区域高度
获得某个元素的内容区域上边界相对于可视区域(即视窗)顶部的距离
示例:假设要获得class="target-element"元素的top属性
var that = this;
wx.createSelectorQuery().select('.target-element').boundingClientRect().exec(function(res) {
if (res[0]) {
var topPosition = res[0].top; // 获取.test元素的上边界位置
// 得到屏幕除去该元素到顶部后剩下部分的高度
that.setData({
height: `calc(100vh - ${topPosition}px)`
});
}
});
获得某个元素的内容区域下边界相对于可视区域(即视窗)顶部的距离
自然的,bottom属性
:元素的内容区域下边界相对于可视区域(即视窗)顶部的距离,和top同理,此处不再赘述
获得某个元素的内容区域高度
注意:获得的高度不包括border、padding和margin。
wx.createSelectorQuery().select('.target-element').boundingClientRect(function(rect) {
if (rect) {
var height = rect.height;
console.log('元素的高度:', height);
}
}).exec();
记录开发过程中遇到的一个de了很久的bug
在子组件中想获取一个元素的高度(用上面的方法),传给父组件,但是获取到的内容一直为null,debug后发现两个原因:
- 在子组件中要用this.createSelectorQuery(),用wx.是错误的
- 函数调用
要在ready()生命周期中或其之后的生命周期中
,否则在这个之前这个元素可能还没渲染出来。导致获取到的内容一直为null(我就一直写在created或attached中,一直不懂为什么null呜呜呜)
资料:
官方文档:自定义组件组件生命周期
官方文档:页面生命周期
在微信小程序中使用vantUI
想在文字中加空格
- text标签
- decode="{{true}}
<text decode="{{true}}">测试 测试</text>
呈现的结果:
官方picker选择器(包括官方提供的省市区选择器)
使用picker
picker
列表左滑右滑删除:
使用vantUI组件库的van-swipe-cell
van-swipe-cell 是一个基于 Vue.js 的组件库 Vant(移动端UI组件库)中的组件之一。van-swipe-cell 组件用于实现滑动操作的列表项,类似于滑动删除或滑动展示更多选项的效果。
通过使用 van-swipe-cell 组件,你可以在列表项上进行左滑或右滑操作,显示隐藏的操作按钮或内容。常见的用途包括滑动删除、标记为已读/未读、收藏等。
页面之间传递参数
在跳转url中附上参数(可以序列化,简单参数也可以不序列化)
然后跳转到的页面中的onLoad函数中通过options获取
如:
let url = `/pages/test`
// 参数序列化,加到url中
const params = `?info=${JSON.stringify(e.currentTarget.dataset.item)}`
wx.navigateTo({
url: url + params
});
onLoad: function(options) {
// 通过 options 参数获取传递的数据
// 将字符串解析转为js对象
const info = JSON.parse(options.info);
// 使用获取到的数据进行相应的操作
console.log(info);
}
// 或:options处写成具体的参数名列表,用{}括起来
onLoad: function({info}) {
// 通过 options 参数获取传递的数据
// 将字符串解析转为js对象
const info = JSON.parse(info);
// 使用获取到的数据进行相应的操作
console.log(info);
}
也可以采用encodeURIComponent
encodeURIComponent 是 JavaScript 中的一个函数,用于将字符串进行 URL 编码。它将字符串中的特殊字符转换为对应的编码形式,以便在 URL 中传递参数时保证参数的正确性和完整性。encodeURIComponent 函数对该字符串进行编码,确保其中的特殊字符(如可能有?这种)被转义为有效的 URL 字符。
这样做的目的是为了将该编码后的参数作为 URL 的一部分,传递给 wx.navigateTo 方法的 url 参数,以便在跳转到 /pages/test页面时,携带和传递该参数。
可以使用 decodeURIComponen
t 函数来完成解码操作。
如:
let url = /pages/test
const params = ?info=${encodeURIComponent(JSON.stringify(e.currentTarget.dataset.item))}
wx.navigateTo({
url: url + params
});
解码:
onLoad: function(options) {
const info = JSON.parse(decodeURIComponent(options.info));
// 使用解码后的参数进行后续操作
// ...
}
实现网格排列的技巧
实现图片如上图这样子每3个排一行,主要是想记录一下CSS方面的实现技巧
主要是想说这一段CSS
其中的.img > view:nth-of-type(3n)
我觉得是个很好的技巧
<view class='img'>
<view wx:for="{{tmpImgList}}" wx:key="index">
<view class='add'>
<!-- 完成上传 -->
<image class="delete" src="/static/images/upload_del.png" bindtap='removeImg' data-index='{{index}}' data-src='{{tmpImgList[index]}}'></image>
<image class='upload' background-size="cover" bindtap='preview' data-url='{{tmpImgList[index]}}' src='{{tmpImgList[index]}}'></image>
</view>
</view>
<view wx:if="{{imgList.length < fileCount}}" class='add' bindtap='addImage'>
<text class='txt'>{{uploadTip}}</text>
</view>
</view>
完整CSS代码:
.img {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
background: #fff;
}
.img > view {
margin-right: 30rpx;
}
// 选择.img 的直接子元素中每隔 3 个 view 元素,将这些被选择的 view 元素的右边距设置为 0,即取消其右侧的空白。
.img > view:nth-of-type(3n) {
margin-right: 0;
}
/* components/uploadImage/uploadImage.wxss */
.img {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
background: #fff;
}
.img > view {
margin-right: 30rpx;
}
// 选择.img 的直接子元素中每隔 3 个 view 元素,将这些被选择的 view 元素的右边距设置为 0,即取消其右侧的空白。
.img > view:nth-of-type(3n) {
margin-right: 0;
}
.img .add {
position: relative;
}
.img .add .upload {
height: 100%;
width: 100%;
border-radius: 20rpx;
}
.img .add .delete {
position: absolute;
right: 0;
top: 0;
height: 32rpx;
width: 32rpx;
}
.img .add {
display: flex;
justify-content: center;
height: 200rpx;
width: 200rpx;
background: #F7F7F7;
border: 1px solid rgba(190, 190, 190, 0.05);
margin-bottom: 30rpx;
border-radius: 20rpx;
}
.img .add .txt {
margin-top: 84rpx;
text-align: center;
display: block;
color: #BEBEBE;
font-size: 24rpx;
line-height: 34rpx;
}
.img .add .icon {
height: 35rpx;
width: 35rpx;
margin-left: auto;
margin-right: auto;
display: block;
margin-top: 7rpx;
}
.img .blur {
filter: blur(1rpx);
background-size: cover;
background-position: center center;
}
.img .loading {
height: 55rpx;
width: 55rpx;
margin-left: auto;
margin-right: auto;
display: block;
margin-top: 35%;
}
view实现网格排列
以每三个一行为例
用到wx:for比较方便
数据(下Card)存在js里,用数组,数组里面可以存一个个{}对象
<view class="card-bg">
<view class="card" wx:for="{{Card}}">
<image mode="widthFix" style="width: 36rpx;" src="{{item.img}}"></image>
<text>{{item.name}}</text>
</view>
</view>
外面套一层display:flex的容器.card-bg,flex-wrap: wrap; 就会自动换行
每个元素大小在.card里具体设置
可以用**:nth-child(3n)**来设置每3n个(即每行最后一个)的样式,如设置margin-right为0,
类似的还有:last-child是设置所有中的最后一个
/* 重点 */
.card-bg{
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: center;
}
.card{
display: flex;
justify-content: center;
align-items: center;
width: 195rpx;
height: 80rpx;
border-radius: 20rpx;
background-color: #f7f7f7;
margin-right: 16rpx;
margin-top: 30rpx;
}
.card:nth-child(3n){ // 注意是card而不是套在外面的card-bg,指定第3、6、9...3n个元素的样式
margin-right: 0rpx;
}
.dazi-card:nth-child(-n+3){ // 指定前三个元素的样式
margin-top: 0rpx;
}
.dazi-card:nth-last-child(-n+3) { // 倒数三个元素
/* 样式规则 */
}