- 小程序拖动浮窗组件的一种实现(可二次封装业务组件使用)
文档 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": {} } [代码]
01-18 - wx.writeBLECharacteristicValue写入成功,打印机没反应?
wx.writeBLECharacteristicValue,调试基础库2.11.3 安卓机
2020-12-03 - 小程序开发 | 点击展示一次性将所有记录全部展开了?如何一条一条展开?
[图片][图片]
2020-08-04 - 实战 | 0~1 自定义组件开发问卷小程序
作者:布道师 韩锴 本文将帮助您基于腾讯云微搭低代码 WeDa 平台,从0到1快速打造如下图所示的问卷调查小程序。 [图片] 概述 基于腾讯云微搭低代码平台开发一款问卷小程序需要经过四个步骤: 1.新建低码应用。 2. 根据需求定义数据源。 3. 按照需求设计页面(主要完成布局的添加和组件的定义)。 4. 本地构建及预览发布。 只需简单几步就可以用腾讯云微搭低代码平台独立开发一款属于自己的应用。 步骤1:新建低码应用 创建应用 1.单击左侧导航栏的【应用管理】,在中间的内容区域单击【创建空白应用】。 [图片] 2. 输入应用名称,单击【确定】创建应用。 [图片] 步骤2:定义数据源 传统开发流程需要先进行需求分析,分析完成后需要按照需求进行数据库的设计,在腾讯云微搭低代码平台中,只需在控制台左侧的【数据源管理】中自定义数据源即可,无需单独构建数据库。 [图片] 1.单击【新建数据源】按钮选择【数据源模型】。 [图片] 2. 在打开的页面里,数据源名称输入问卷调查,数据源标识输入 survey。 [图片] 3. 单击【添加字段】按钮,添加数据源相关字段。 [图片] 结合实际情况设置以下参数: 字段名称:输入[代码]姓名[代码]。 字段标识:输入[代码]name[代码]。 数据类型:选择【字符串】。 是否必填:选择【是】。 是否枚举:选择【否】。 [图片] 类似地,依次添加字段 phone、job、industry。如下图 所示。 4.由于参与问卷调查用户只需提交即可,因此设置【动作】时只需勾选【新增】方法,其他均保持默认。设置完毕后需要单击页面底部的【立即创建】按钮,否则刚才添加的字段都不生效。 [图片] 步骤3:设计页面 创建页面 1.数据源设置完毕后就需要创建页面,单击【应用管理】,找到刚才创建的应用,单击【编辑】按钮进入应用编辑器。 [图片] 2. 编辑器分为四个部分,可归纳为导航条,组件选择区,编辑区,和属性面板。 [图片] 功能设计 首先需要构思设计小程序的布局。对于调查问卷,通常采用垂直布局,此处将页面分成三个部分,分别是头部、内容、尾部。 头部:通常放置小程序的介绍,向用户告知本次调查的目的。 内容:部分是具体的调查项和提交按钮。 尾部:一般是放置版权信息等补充信息。 设计完功能和布局后,就可以按照实际需求进行页面开发。 引入数据源 1.本项目的目的是让用户填写问卷调查,再将内容保存到数据库中,所以需要先为问卷引入数据源。单击导航条上的【变量管理】。 [图片] 2. 在打开的页面找到【首页 index】下边的【状态变量】,单击旁边的【+】号,依次录入变量标识和变量名为 survey,变量类别选择【数据源模型】,数据源选择【问卷调查(survey)】,变量类型选择【新纪录】,变量更新动作选择【创建单条记录】,设置好后单击【提交】按钮。 [图片] 布局创建 在左侧的控制面板切换到【组件】页签,然后在布局里单击【垂直布局】进行布局创建。 [图片] 头部编写 1.头部信息需要先加入一个容器组件:选中大纲树中的【插槽header】,并单击通用组件中的【容器】组件,就可以把容器组件放入插槽 header 中。您也可以通过拖拽实现上述操作。 [图片] 2. 在容器组件内放入文本组件。选中容器组件后,在左侧的组件面板中单击【文本】组件,并在文本组件【数据】>【文本内容】中修改文本的内容。 内容示例: 文本内容:尊敬的腾讯云微搭低代码用户,为了更好地提升腾讯云微搭低代码平台的体验和服务,我们特展开本次的问卷调查,希望能得到您的真实想法与宝贵意见,本问卷将花费您5分钟时间。 [图片] 3. 同时,可根据业务需求在右侧的组件编辑区调整视觉样式。例如,选中文本组件所在的【容器】组件,选择【组件编辑】>【样式】,将组件的内边距左右各设置20个单位距离。 [图片] 内容编写 1.选中【插槽 content】,单击【容器】组件,在插槽 content 中放入容器组件。 [图片] 2. 选中【容器】组件,单击【表单容器】组件。 [图片] 3. 依次加入调查项,如此案例中调查项分为姓名、手机、职业和行业。单击表单容器下的【插槽 contentSlot】,并在该插槽中依次添加相关表单组件。姓名选择【表单输入】,手机选择【表单手机号码】,职业和行业都选择【表单单选】。 !表单组件都是添加在【插槽 contentSlot】下的平级的组件。 [图片] 4. 下面开始修改表单组件的内容,首先是姓名。单击【表单输入】组件,表单字段名称设置为 name,【标题】设置为【姓名】,【是否必填】开关设置为【开】。 [图片] 5. 单击【表单手机号码】组件,设置该组件的表单字段名称为 phone,标题为手机,是否必填开关设置为开。 [图片] 6. 单击【表单单选】组件,设置表单字段名称(字段名称填写为 job),组件的标题(我的职业是),将布局方式改为垂直,并依次增加单选项的内容,单选项名称分别为前端开发、后台开发、设计师、运营、产品策划、其他,单选项的值分别设置为 first、second、third、fourth、five、six。单选内容的 value 会被提交到数据库里。 [图片] 7. 按照同样的方法增加所属行业调查项,字段名称需要填写为 industry,标题设置为“我所属的行业是”,单选项名称分别为金融、工业、教育、医疗、政务、IT互联网、其他,单选项的值分别为 first、second、third、fourth、five、six、seven。单选内容的 value 会被提交到数据库里。 [图片] 8. 调查项添加完毕后,给调查表内容底部增加提交按钮。按钮放置在表单容器的插槽中,与表单组件平级,以关联到同容器内的表单组件数据。选中大纲树的【表单容器】>【插槽 contentSlot】,单击表单类目中的【按钮】组件。将按钮组件的【标题】修改为确认提交,将【用于form组件】设置为【提交】。 [图片] 9. 选择【表单容器】,切换到【事件】页签,选择事件为 submit。 [图片] 10. 选择数据源,单击【确定添加】。 [图片] 11. 数据源名称选择问卷调查,方法名设置为 创建单条记录(create),传入参数设置为 event.detail。 类似地,增加点击提交按钮后的提示内容。 添加触发条件【dataSource 成功】,动作类型【平台方法】,执行动作为【showToast 显示信息】,点击确认添加,并将标题设为【提交成功】,图标为 success。 添加触发条件【dataSource 失败】,动作类型【平台方法】,执行动作为【showToast 显示信息】,点击确认添加,并将标题设为【提交失败】,图标为 error。 [图片] 尾部编写 选中【插槽 footer】,单击组件通用类目中的【文本】组件,并将文本内容设置为版权信息。 [图片] 步骤4:代码构建与发布 1.代码改造好后就可以进行预览,单击导航条【预览发布】。为快速测试,您可以选择部署方式为【云端】,部署平台为【网页h5】。 [图片] 2. 本地需要安装好 nodejs 并且按照弹出窗口提示的命令依次在命令行执行,安装完毕后需要打开低代码的编译监控。 [图片] 3. 部署完成后便会弹出预览二维码和预览的访问地址。 [图片] 4. 构建成功后可以用手机扫描二维码浏览效果。 [图片] 数据管理 用户填写了问卷调查后,管理员可以单击【数据源管理】,查看用户提交的问卷信息数据,单击【数据管理后台】,腾讯云微搭低代码 LowCode 平台自带内容管理(CMS)后台可以查看和管理数据。 [图片] 进入页面后可以看到已创建的历史项目,点击刚刚创建的新项目。 [图片] 选中表单即可查看数据。 [图片] 您也可以直接在控制台的【应用管理】中找到刚才的应用,点击应用卡片,在【数据管理后台】中找到预览/发布的应用所对应的数据。【正式数据】对应的是使用发布产生的应用数据,【测试数据】是使用预览产生的应用数据。 [图片] 产品介绍 腾讯云微搭低代码是高效、高性能的拖拽式低代码开发平台,向上连接前端的行业业务,向下连接云计算的海量能力,助力企业垂直上云。腾讯云微搭低代码将繁琐的底层架构和基础设施抽象化为图形界面,通过行业化模板、拖放式组件和可视化配置快速构建多端应用(小程序、H5应用、Web 应用等),免去了代码编写工作,让您能够完全专注于业务场景。腾讯云微搭低代码以云开发作为底层支撑,云原生能力将应用搭建的全链路打通,提供高度开放的开发环境,且时刻为您的应用保驾护航。 开通低代码:https://cloud.tencent.com/product/lowcode 产品文档:https://cloud.tencent.com/document/product/1301/48874 技术交流加Q群:1003059706 最新资讯关注微信公众号【腾讯云云开发】
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