- 小程序拖动浮窗组件的一种实现(可二次封装业务组件使用)
文档 Fab 浮动按钮 可拖动的悬浮窗按钮 Props 参数 说明 类型 可选值 默认值 position 距离对象 Boolean – {left:0,right:0,top:0,bottom:0} left 左边距离(无需单位) Number – 0 right 右边距离(无需单位) Number/String – 0 top 顶部距离(无需单位) Number/String – 0 bottom 底部距离(无需单位) Number/String – 0 h-margin 拖动后的水平方向最小边距(左右边距) Number/String – 10px v-margin 拖动后的垂直方向最小边距(上下边距) Number/String – 10px 注:rpx单位对应的是750的屏幕,上述属性取值使用375下的数值,如果是750设计稿在使用时需手动除2传入 浮动按钮位置仅推荐left、top / right 、bottom 两两使用,默认优先使用bottom、right配置 Slots name 说明 default 悬浮窗默认插槽,用户可自定义内容及大小 Events 无 Methods 无 使用示例 支持二次封装业务组件以复用 [代码]<!-- 375设计稿下位于右下10rpx、100rpx的浮动按钮 --> <c-fab bottom="100" right='10'> <view class="float" style="width:100rpx;height:100rpx;border-radius: 99em;background:#fad84c;color:#333;display:flex;align-items:center;justify-content: center;">活动</view> </c-fab> [代码] 完整实现代码 [代码]<movable-area> <movable-view bind:touchend="onTouchend" bind:touchmove="onTouchMove" bind:touchstart="addAnimation" animation="{{animation}}" style="width:{{elementWidth}}px;height:{{elementHeight}}px" x="{{x}}" y="{{y}}" direction="all"> <view class="float-box" > <slot></slot> </view> </movable-view> </movable-area> [代码] [代码]Component({ /** * 组件的属性列表 */ properties: { position: { type: Object, value: { left: 0, right: 0, bottom: 0, top: 0 } // left、top、right、bottom }, left: { type: Number, value: 0 }, right: { type: Number, value: 0 }, top: { type: Number, value: 0 }, bottom: { type: Number, value: 0 }, hMargin: { // 拖动后的水平方向最小边距(左右边距) type: Number, value: 10 }, vMargin: { // 拖动后的垂直方向最小边距(上下边距) type: Number, value: 10 } }, data: { x: 999, y: 999, windowWidth: wx.getSystemInfoSync().windowWidth, windowHeight: wx.getSystemInfoSync().windowHeight, elementWidth: 0, elementHeight: 0, animation: false, isMoved: false // 是否拖动 }, lifetimes: { attached() { // 初始化位置 wx.createSelectorQuery().in(this).select('.float-box').boundingClientRect().exec((res) => { console.log(233, res); this.data.elementWidth = res[0].width; this.data.elementHeight = res[0].height; if (this.properties.position.left || this.properties.left) { this.data.x = this.properties.position.left || this.properties.left; } if (this.properties.position.right || this.properties.right) { this.data.x = this.data.windowWidth - this.data.elementWidth - (this.properties.position.right ? this.properties.position.right : this.properties.right); } if (this.properties.position.top || this.properties.top) { this.data.y = this.properties.position.top || this.properties.top; } if (this.properties.position.bottom || this.properties.bottom) { this.data.y = this.data.windowHeight - this.data.elementHeight - (this.properties.position.bottom ? this.properties.position.bottom : this.properties.bottom); } this.setData({ elementWidth: this.data.elementWidth, elementHeight: this.data.elementHeight, x: this.data.x, y: this.data.y }); }); } }, /** * 组件的方法列表 */ methods: { onTouchend(e) { console.log(this.data.isMoved, this.data.x, e.changedTouches[0].clientX, this.data.elementWidth); if (!this.data.isMoved) return; const currentX = e.changedTouches[0].clientX; let currentY = e.changedTouches[0].clientY; if (currentY <= this.properties.vMargin) { currentY = this.properties.vMargin + this.data.elementHeight / 2; } if (currentY >= this.data.windowHeight - this.properties.vMargin) { currentY = this.data.windowHeight - this.properties.vMargin - this.data.elementHeight / 2; } if (currentX + this.data.elementWidth / 2 > this.data.windowWidth / 2) { this.setData({ x: this.data.windowWidth - this.properties.hMargin - this.data.elementWidth, y: currentY - this.data.elementHeight / 2 }); } if (currentX + this.data.elementWidth / 2 <= this.data.windowWidth / 2) { this.setData({ x: this.properties.hMargin, y: currentY - this.data.elementHeight / 2 }); } }, addAnimation() { this.data.isMoved = false; if (!this.data.animation) { this.setData({ animation: true }); } }, onTouchMove() { this.data.isMoved = true; } } }); [代码] [代码]movable-area { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 50; movable-view { pointer-events: auto; //可以点击 } .float-box { display: inline-block; } } [代码] [代码]{ "component": true, "usingComponents": {} } [代码]
2024-01-18 - wx.writeBLECharacteristicValue写入成功,打印机没反应?
wx.writeBLECharacteristicValue,调试基础库2.11.3 安卓机
2020-12-03 - 小程序开发 | 点击展示一次性将所有记录全部展开了?如何一条一条展开?
[图片][图片]
2020-08-04 - 2021-06-10
- 极简代码之云开发的触底无限加载
js: [代码]const db = wx.cloud.database() const _ = db.command const col = "test" const sql = { _id: _.neq(1) } //获取所有记录 Page({ data: { isEndOfList: false, list: [], limit: 20 //每次拉取数量 }, onLoad: function(options) { this.getData() }, getData: function() { db.collection(col) .where(sql) .skip(this.data.list.length) .limit(this.data.limit) .get() .then(res => { this.setData({ list: [...this.data.list, ...res.data], //合并数据 isEndOfList: res.data.length < this.data.limit ? true : false //判断是否结束 }) }) }, onReachBottom: function() { this.data.isEndOfList || this.getData() } }) [代码] wxml [代码]<view style="height:100px" wx:for='{{list}}' wx:key='none'>{{index}}</view> <view style="padding:15px;text-align:center;color:grey" wx:if='{{list.length>limit}}'> <view wx:if='{{(!isEndOfList)}}'>正在加载数据...</view> <view wx:else>----END----</view> </view> [代码]
2020-06-16 - 微信小程序云函数分页加载
公用前端代码 <view class=“post grid” wx:for="{{list}}" wx:key=“id”> <view class=“headline”>{{item.title}}</view> </view> 云函数分页方式代码 // 云函数入口文件 const cloud = require(‘wx-server-sdk’) cloud.init() const db=cloud.database(); // 云函数入口函数 exports.main = async (event, context) => { return await db.collection(“hdllinggan”).orderBy(“orderid”,“desc”) .skip(event.len)//分页 .limit(event.pageNum)//每页加载多少 .get() } 页面js调用代码 Page({ data: { list: [], }, getData(e) { // console.log(e.currentTarget.dataset.page) let page = e.currentTarget.dataset.page - 1 console.log(“计算以后的page”, page) this.getList() }, getList() { wx.showLoading({ //设置加载中图标 title: ‘加载中。。。。。’, }) console.log(“当前list的长度”, this.data.list.length) let len = this.data.list.length [代码]//调用云函数 wx.cloud.callFunction({ name: "hdllinggan", data: { pageNum: 10,//每页加载多少 len: len,//分页用的 } }).then(res => { wx.hideLoading() //加载完成后隐藏加载图标 console.log("调用成功", res) if (res.result.data.length <= 0) { //没有更多数据的友好提示 wx.showToast({ icon: "none", title: '没有更多数据了', }) } this.setData({ // list: res.data list: this.data.list.concat(res.result.data) }) }).catch(err => { wx.hideLoading() //加载完成后隐藏加载图标 console.log("调用失败", err) }) [代码] }, /** 生命周期函数–监听页面加载 */ onLoad: function (options) { this.getList(0) }, /** 页面上拉触底事件的处理函数 */ onReachBottom: function () { this.getList() }, })
2022-01-25 - 几句代码理解async/await的用法
运行一下几句代码,立马就能理解async/await怎么使用了: testAsync: async function () { let res = await wx.showModal({ content: 'step1?' }) if (res.confirm) { } else return await this.step1() res = await wx.showModal({ content: 'step2?' }) if (res.confirm) { } else return await this.step2() console.log('end') }, step1: async function () { await wx.showModal({ content: 'this is step1' }) console.log('end of step1') }, step2: async function () { let res = await wx.showActionSheet({ itemList: ['A', 'B'], }).catch(err => console.log('err:', err))//catch可以防止阻断 if (res.tapIndex == 0) { console.log('A') } if (res.tapIndex == 1) { console.log('B') } console.log('end of step2') },
2021-12-16 - 微信小程序如何实现页面传参?
前言 只要你的小程序超过一个页面那么可能会需要涉及到页面参数的传递,下面我总结了 4 种页面方法。 路径传递 通过在url后面拼接参数,参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 ‘path?key=value&key2=value2’。 案例:A页面带参数跳转到B页面 A页面跳转代码 [代码]goB(){ wx.navigateTo({ url: '/pages/B/index?id=value', }) }, [代码] B页面接收代码 [代码]onLoad: function (options) { console.log('id', options.id) } [代码] 上面的案例是字符串参数,但是很多情况下需要传递对象,如下方代码。 [代码]Page({ data: { userInfo:{ name:'cym', age:16 } }, goB(){ wx.navigateTo({ url: '/pages/B/index?id='+this.data.userInfo, }) }, }) [代码] 如果使用上面同样的方式结构,输出的结果是:[object Object] 这个时候需要先把对象通过JSON.stringify(obj)将 object 对象转换为 JSON 字符串进行参数传递,再到接收页面通过JSON.parse解析使用。 A页面跳转代码 [代码] goB(){ let userStr = JSON.stringify(this.data.userInfo) wx.navigateTo({ url: '/pages/B/index?id='+userStr, }) } [代码] B页面接收代码 [代码]onLoad: function (options) { console.log('id', JSON.parse(options.id)) } [代码] 全局变量 通过App全局对象存放全局变量。 app.js代码 [代码]App({ // 存放对象的全局变量 globalData:{}, }) [代码] A页面跳转代码 [代码]// 获取App对象 const app = getApp() Page({ /** * 页面的初始数据 */ data: { userInfo: { name: 'cym', age: 16 } }, goB() { app.globalData.userInfo = this.data.userInfo wx.navigateTo({ url: '/pages/B/index', }) }, }) [代码] B页面接收代码 [代码]// 获取全局对象 const app = getApp() Page({ onLoad: function (options) { console.log(app.globalData.userInfo) } }) [代码] 存放在 App 全局变量里面,可以被多个页面使用,直接从 App 对象获取即可。这个数据是保持在内测中,每次小程序销毁就没有了。 数据缓存 通过存储到数据缓存中。 A页面跳转代码 [代码] goB() { wx.setStorageSync('userInfo', this.data.userInfo) wx.navigateTo({ url: '/pages/B/index', }) } [代码] B页面接收代码 [代码] onLoad: function (options) { let userInfo = wx.getStorageSync('userInfo', this.data.userInfo) console.log(userInfo) } [代码] 存放在数据缓存里面,可以被多个页面使用,直接用 getStorageSync 获取即可。这个数据是保持在数据缓存中,除非清楚数据缓存或者删除小程序否则一直存在。 事件通信 通过事件通信通道。 A页面跳转代码 [代码]goB() { wx.navigateTo({ url: '/pages/B/index', success:(res)=>{ // 发送一个事件 res.eventChannel.emit('toB',{ userInfo: this.data.userInfo }) } }) } [代码] B页面接收代码 [代码]onLoad: function (options) { // 获取所有打开的EventChannel事件 const eventChannel = this.getOpenerEventChannel(); // 监听 index页面定义的 toB 事件 eventChannel.on('toB', (res) => { console.log(res.userInfo) }) } [代码] 总结 大家可以针对具体业务场景来进行选择合适自己的传参方式。
2022-02-19