uniapp 多环境配置打包,比较优雅的解决方案
uniapp 多环境配置打包,比较优雅的解决方案
读取.env.[development|test|staging|production]配置文件进行打包,最终效果如下图可以看到多个环境,
并且我们可以自定义更多的环境配置
前言
由于uniapp的hbuilder开发工具,只提供了development和production的环境编译方式,一般来说,只能做到development和production两个环境的区分。在实际开发中,我们如果有多个环境开发需求和打包需求,尤其是配置多个环境的接口请求地址等配置。
针对这种情况,我在网上找了很多相关的资料,基本都是命令行的方案,使用uniapp的scripts方案也有,但是是把配置信息写到scripts上的,这解决方案也不够优雅,如果有多个配置就显得很拥肿了。
下面,我们一步一步来配置实现如何根据编译环境读取对应的.env文件加载到项目中。(下面只讲vite配置的方式,webpack的配置方式有空再补充)
配置实现
- 项目根目录,自行新增对应的配置文件
- 在package.json文件添加uni-app的scripts,需要配置几个环境就添加几个,关于这个配置的意思,可以去查看其他相关的文档,这里不展开讲述。
配置好后,点击运行和发行就能看到对应的环境选择项了
此时只是有对应的环境选择项,接下来的思路就是,判断对应的script执行环境,来加载不同的.env配置文件,读取到项目中
- 修改vite.config.js文件,重点看注释
import { loadEnv } from 'vite';
import uni from '@dcloudio/vite-plugin-uni';
// import viteCompression from 'vite-plugin-compression';
// https://vitejs.dev/config/
export default (command, mode) => {//uniapp中,这个mode,不用命令行的添加--mode编译的话,是undefined的
let env = undefined;
if(!mode){//这里是为了确保mode有值,假如开发人员直接在开发工具选择编译到浏览器,也能兼容到
if(process.env.NODE_ENV=='production'){
mode = 'production'
}else{
mode = 'development'
}
}
switch (process.env.UNI_SCRIPT){//这个就是第三步配置的uni-app的script,一一对应判断
case 'dev-h5':
mode = 'development';
break;
case 'test-h5':
mode = 'test'
break;
case 'stage-h5':
mode = 'staging'
break;
case 'prod-h5':
mode = 'production'
break;
}
env = loadEnv(mode, __dirname,"APP")
console.log(`编译${mode}环境`)
console.log(env);//此时已经把env配置读取到了,并且这是个json格式,
return {//别试图在这里定义mode,试过了,在uniapp中不起作用,目前方案只想到了用define来做
envPrefix:'APP_',
plugins: [
uni()
],
server: {
host: true,
// open: true,
port: env.APP_PORT,
hmr: {
overlay: true,
},
},
define:{//根据vite的官方文档,可以把define定义的变量名,在项目编译时,识别项目文件中的这个变量名直接替换成env配置,我们把这个变量放到config.js文件中,对env配置进行集中管理
__VITE_ENV__:JSON.stringify(env)
}
};
};
- 接下来在项目中由一个config.js文件来集中管理env相关的配置,再暴露出来给其他业务模块调用。
至此,uniapp的多环境配置已经完成!!!
如果需要命令行配置打包,可以参考其他的博客,直接配置命令行就可以,命令行写--mode参数即可。
uniapp 多环境配置打包,比较优雅的解决方案
读取.env.[development|test|staging|production]配置文件进行打包,最终效果如下图可以看到多个环境,
并且我们可以自定义更多的环境配置
前言
由于uniapp的hbuilder开发工具,只提供了development和production的环境编译方式,一般来说,只能做到development和production两个环境的区分。在实际开发中,我们如果有多个环境开发需求和打包需求,尤其是配置多个环境的接口请求地址等配置。
针对这种情况,我在网上找了很多相关的资料,基本都是命令行的方案,使用uniapp的scripts方案也有,但是是把配置信息写到scripts上的,这解决方案也不够优雅,如果有多个配置就显得很拥肿了。
下面,我们一步一步来配置实现如何根据编译环境读取对应的.env文件加载到项目中。(下面只讲vite配置的方式,webpack的配置方式有空再补充)
配置实现
- 项目根目录,自行新增对应的配置文件
- 在package.json文件添加uni-app的scripts,需要配置几个环境就添加几个,关于这个配置的意思,可以去查看其他相关的文档,这里不展开讲述。
配置好后,点击运行和发行就能看到对应的环境选择项了
此时只是有对应的环境选择项,接下来的思路就是,判断对应的script执行环境,来加载不同的.env配置文件,读取到项目中
- 修改vite.config.js文件,重点看注释
import { loadEnv } from 'vite';
import uni from '@dcloudio/vite-plugin-uni';
// import viteCompression from 'vite-plugin-compression';
// https://vitejs.dev/config/
export default (command, mode) => {//uniapp中,这个mode,不用命令行的添加--mode编译的话,是undefined的
let env = undefined;
if(!mode){//这里是为了确保mode有值,假如开发人员直接在开发工具选择编译到浏览器,也能兼容到
if(process.env.NODE_ENV=='production'){
mode = 'production'
}else{
mode = 'development'
}
}
switch (process.env.UNI_SCRIPT){//这个就是第三步配置的uni-app的script,一一对应判断
case 'dev-h5':
mode = 'development';
break;
case 'test-h5':
mode = 'test'
break;
case 'stage-h5':
mode = 'staging'
break;
case 'prod-h5':
mode = 'production'
break;
}
env = loadEnv(mode, __dirname,"APP")
console.log(`编译${mode}环境`)
console.log(env);//此时已经把env配置读取到了,并且这是个json格式,
return {//别试图在这里定义mode,试过了,在uniapp中不起作用,目前方案只想到了用define来做
envPrefix:'APP_',
plugins: [
uni()
],
server: {
host: true,
// open: true,
port: env.APP_PORT,
hmr: {
overlay: true,
},
},
define:{//根据vite的官方文档,可以把define定义的变量名,在项目编译时,识别项目文件中的这个变量名直接替换成env配置,我们把这个变量放到config.js文件中,对env配置进行集中管理
__VITE_ENV__:JSON.stringify(env)
}
};
};
- 接下来在项目中由一个config.js文件来集中管理env相关的配置,再暴露出来给其他业务模块调用。
至此,uniapp的多环境配置已经完成!!!
如果需要命令行配置打包,可以参考其他的博客,直接配置命令行就可以,命令行写--mode参数即可。
vue3+vite6+vant4仿deepseek/chatgpt流式ai聊天会话
基于vue3+deepseek实战纯撸一款仿DeepSeek/ChatGPT流式聊天AI对话聊天。
集成Vue3 对接 DeepSeek Web API 流式打字输出对话大模型。支持代码高亮、本地缓存,支持移动端+PC端完美显示。
项目结构
特性
- 流式响应:逐字显示 AI 回复,提供更好的用户体验
优雅的 UI 设计:- 气泡式对话界面
- 打字机效果
- 平滑的动画过渡
- 响应式布局
想要了解更多的技术实现细节可以去参考下面这篇分享文章。
Vue3-DeepSeek流式AI聊天|vite6+vant4+deepseek智能ai对话助手
基于vue3+deepseek实战纯撸一款仿DeepSeek/ChatGPT流式聊天AI对话聊天。
集成Vue3 对接 DeepSeek Web API 流式打字输出对话大模型。支持代码高亮、本地缓存,支持移动端+PC端完美显示。
项目结构
特性
- 流式响应:逐字显示 AI 回复,提供更好的用户体验
优雅的 UI 设计:- 气泡式对话界面
- 打字机效果
- 平滑的动画过渡
- 响应式布局
想要了解更多的技术实现细节可以去参考下面这篇分享文章。
Vue3-DeepSeek流式AI聊天|vite6+vant4+deepseek智能ai对话助手
最近更新的HBuilder,卡巴基斯频繁警报并删除Hbuilder
事件: 检测到恶意对象
应用程序: HBuilder X
用户: X\xzm
用户类型: 活动用户
组件: 系统监控
结果说明: 检测到
类型: 木马
名称: PDM:Trojan.Win32.Generic
威胁级别: 高
对象类型: 进程
对象路径: d:\developertools\hbuilderx
对象名称: hbuilderx.exe
原因: 数据库
数据库发布日期: 昨天,2025/3/15 20:55:00
事件: 检测到恶意对象
应用程序: HBuilder X
用户: X\xzm
用户类型: 活动用户
组件: 系统监控
结果说明: 检测到
类型: 木马
名称: PDM:Trojan.Win32.Generic
威胁级别: 高
对象类型: 进程
对象路径: d:\developertools\hbuilderx
对象名称: hbuilderx.exe
原因: 数据库
数据库发布日期: 昨天,2025/3/15 20:55:00
有懂uniapp+unicloud+uview的小伙伴想可以联系呀!
最近我想开发一个项目是小程序类的,部分页面需要小伙伴协助开发
如果你懂得uniapp+unicloud+uview那么非常欢迎您联系我呀
有偿的,有偿,有偿!重要的事情说三遍。
兼职类的哦不是全职,欢迎联系呀。
最近我想开发一个项目是小程序类的,部分页面需要小伙伴协助开发
如果你懂得uniapp+unicloud+uview那么非常欢迎您联系我呀
有偿的,有偿,有偿!重要的事情说三遍。
兼职类的哦不是全职,欢迎联系呀。
自动化测试, 一直报Failed to connect to runtime,调试自定义基座
我一直报错是因为在 env.js 里面设置了自定义基座,设置的不正确。
两种解决方案
1、不跑自定义基座,把env.js、jest.config.js 删除掉,重新自动化测试,他会重新生成初始文件就可以跑app标准基座了
2、根据我下面的图片,在env.js 里面设置自定义基座配置,自定义基座的包路径一定要正确。
我一直报错是因为在 env.js 里面设置了自定义基座,设置的不正确。
两种解决方案
1、不跑自定义基座,把env.js、jest.config.js 删除掉,重新自动化测试,他会重新生成初始文件就可以跑app标准基座了
2、根据我下面的图片,在env.js 里面设置自定义基座配置,自定义基座的包路径一定要正确。
收起阅读 »uni-steps 组件左侧的线和点显示异常
描述:
uni-app 开发微信小程序,uni-steps 组件左侧的线和点显示异常。
解决办法:
在 uni-steps 组件上加一个判断,当列表不为空的时候才渲染组件,下面示例代码中 listArry 就是节点列表。
<uni-steps v-if="listArry.length > 0" ></uni-steps>
原因:
uni-steps 组件渲染时会获取右侧文本的高度,并且 +1 后作为左侧点线的高度,当节点列表为空,右侧没有文本信息,获取到的高度是 undefined,导致显示异常。
描述:
uni-app 开发微信小程序,uni-steps 组件左侧的线和点显示异常。
解决办法:
在 uni-steps 组件上加一个判断,当列表不为空的时候才渲染组件,下面示例代码中 listArry 就是节点列表。
<uni-steps v-if="listArry.length > 0" ></uni-steps>
原因:
uni-steps 组件渲染时会获取右侧文本的高度,并且 +1 后作为左侧点线的高度,当节点列表为空,右侧没有文本信息,获取到的高度是 undefined,导致显示异常。
IOS系统的input文本框的输入法有问题
iPhone手机, input文本框弹出的输入法只有繁体手写功能,没有键盘。
此时我把手机的地区从mei国改成zhongguodalu就正常了。
iPhone手机, input文本框弹出的输入法只有繁体手写功能,没有键盘。
此时我把手机的地区从mei国改成zhongguodalu就正常了。
【插件大赛】2025年DCloud插件大赛评选结果出炉【鸿蒙征文】大量优秀的uni-app鸿蒙开发实践博文涌现,欢迎阅读学习!【云打包】DCloud云打包计费规则调整
1.2025年DCloud插件大赛评选结果公布
为进一步繁荣uni生态,特别是推动鸿蒙平台的生态建设,惠及产业和开发者,DCloud 正式启动「2025年度插件大赛」。
大赛评选结果已公布,获奖作品详见
2.【鸿蒙征文】分享你的uni-app鸿蒙开发实践,大量优秀博文涌现
在1024程序员节即将到来之际,DCloud 诚挚邀请您参与本次 “星光不负,码向未来” 鸿蒙主题征文活动。
我们特别希望看到基于 uni-app 和 uni-app x 在鸿蒙生态中的开发实践、经验总结与创新思考。无论是开发鸿蒙App、元服务,还是打造兼容鸿蒙的插件/UI库,你的每一行代码和每一次分享,都将是鸿蒙生态建设中闪耀的星光。
优秀博文除了获得精美奖品外,还将有机会获得 DCloud官方推荐 和 HarmonyOS开发者社区联合曝光,让你的技术影响力更进一步!
目前已有很多开发者贡献大量优秀博文,欢迎大家阅读学习,详情
3.DCloud云打包计费规则调整公告
详见:https://ask.dcloud.net.cn/article/42315
4.腾讯云服务空间套餐升级
腾讯云服务空间套餐于2025年6月30日进行升级,升级针对部分套餐额度和能力进行了调整
- 套餐版本新增及下线各三个,已有套餐用户不受影响可继续使用、续费
- 新增套餐及现有的个人版套餐资源配额提升,部分配额提升50% ~ 100%,个人版套餐资源配额提升已实时生效
- 199元以下套餐,即个人版、入门版两个套餐将不再支持固定出口IP和数据库回档能力,如有需求可升级更高套餐版本
更多详见相关公告
5.vue2项目sass编译器调整
HBuilderX 4.5+起,vue2的sass编译器由node-sass改为dart-sass。node-sass是已经被淘汰的不再维护的库,且不支持arm cpu。
node-sass有些过期语法在dart-sass上报错导致无法编译。
虽然默认为dart-sass,但HBuilderX 4.56版也提供了选项,可以手动选择node-sass。在manifest.json中根节点配置"sassImplementationName": "node-sass"。
注意这个回退选项的生效范围是:vue2项目且HBuilderX不是arm版。
vue3一直都是dart-sass,不需要node-sass的选项;
node-sass本身不支持arm cpu。
如果开发者的mac电脑是arm cpu且仍想要为vue2项目使用node-sass,需要改用HBuilderX的mac intel cpu版。intel 版也可以以兼容模式在mac的arm cpu上运行。
当然我们仍然推荐开发者修改不兼容的代码,适配dart-sass,这2种sass编译器的常见语法差异及修改方案见:文档
HBuilderX 4.55没有回退选项,请开发者升级到HBuilderX 4.56。
6. HBuilderX Mac版推出了arm专版,适配M系列CPU
在HBuilderX官网下载时,请注意选择mac的intel版(也称为x86版)和arm版(也称为m系列cpu版)。
intel版也可以用于arm CPU。但arm版仅能在M系列CPU上运行。
下载地址详见:https://www.dcloud.io/hbuilderx.html
注意node-sass自身不支持arm,所以arm版HBuilderX仅能使用dart-sass。
7. HBuilderX在linux平台推出了cli版本,方便工程自动化和持续集成
1.2025年DCloud插件大赛评选结果公布
为进一步繁荣uni生态,特别是推动鸿蒙平台的生态建设,惠及产业和开发者,DCloud 正式启动「2025年度插件大赛」。
大赛评选结果已公布,获奖作品详见
2.【鸿蒙征文】分享你的uni-app鸿蒙开发实践,大量优秀博文涌现
在1024程序员节即将到来之际,DCloud 诚挚邀请您参与本次 “星光不负,码向未来” 鸿蒙主题征文活动。
我们特别希望看到基于 uni-app 和 uni-app x 在鸿蒙生态中的开发实践、经验总结与创新思考。无论是开发鸿蒙App、元服务,还是打造兼容鸿蒙的插件/UI库,你的每一行代码和每一次分享,都将是鸿蒙生态建设中闪耀的星光。
优秀博文除了获得精美奖品外,还将有机会获得 DCloud官方推荐 和 HarmonyOS开发者社区联合曝光,让你的技术影响力更进一步!
目前已有很多开发者贡献大量优秀博文,欢迎大家阅读学习,详情
3.DCloud云打包计费规则调整公告
详见:https://ask.dcloud.net.cn/article/42315
4.腾讯云服务空间套餐升级
腾讯云服务空间套餐于2025年6月30日进行升级,升级针对部分套餐额度和能力进行了调整
- 套餐版本新增及下线各三个,已有套餐用户不受影响可继续使用、续费
- 新增套餐及现有的个人版套餐资源配额提升,部分配额提升50% ~ 100%,个人版套餐资源配额提升已实时生效
- 199元以下套餐,即个人版、入门版两个套餐将不再支持固定出口IP和数据库回档能力,如有需求可升级更高套餐版本
更多详见相关公告
5.vue2项目sass编译器调整
HBuilderX 4.5+起,vue2的sass编译器由node-sass改为dart-sass。node-sass是已经被淘汰的不再维护的库,且不支持arm cpu。
node-sass有些过期语法在dart-sass上报错导致无法编译。
虽然默认为dart-sass,但HBuilderX 4.56版也提供了选项,可以手动选择node-sass。在manifest.json中根节点配置"sassImplementationName": "node-sass"。
注意这个回退选项的生效范围是:vue2项目且HBuilderX不是arm版。
vue3一直都是dart-sass,不需要node-sass的选项;
node-sass本身不支持arm cpu。
如果开发者的mac电脑是arm cpu且仍想要为vue2项目使用node-sass,需要改用HBuilderX的mac intel cpu版。intel 版也可以以兼容模式在mac的arm cpu上运行。
当然我们仍然推荐开发者修改不兼容的代码,适配dart-sass,这2种sass编译器的常见语法差异及修改方案见:文档
HBuilderX 4.55没有回退选项,请开发者升级到HBuilderX 4.56。
6. HBuilderX Mac版推出了arm专版,适配M系列CPU
在HBuilderX官网下载时,请注意选择mac的intel版(也称为x86版)和arm版(也称为m系列cpu版)。
intel版也可以用于arm CPU。但arm版仅能在M系列CPU上运行。
下载地址详见:https://www.dcloud.io/hbuilderx.html
注意node-sass自身不支持arm,所以arm版HBuilderX仅能使用dart-sass。
7. HBuilderX在linux平台推出了cli版本,方便工程自动化和持续集成
收起阅读 »uni-app 实现好看易用的抽屉效果
一. 前言
我之前使用 uni-app 和 uniCloud 开发了一款软考刷题应用,在这个应用中,我使用了抽屉组件来实现一些功能,切换题库,如下图所示:
在移动应用开发中,抽屉(Drawer)是一种常见的界面设计模式,这个组件可以在需要侧边导航或者额外信息展示的地方使用。它允许用户通过侧滑的效果打开一个菜单或额外的内容区域。
这种设计不仅能够节省屏幕空间,还能提供一种直观的交互方式。
例如,在电商应用中,可以将购物车或分类列表放在抽屉里;在新闻阅读器中,可以放置频道选择等;而在有题记刷题软件中,我主要用于题库的选择功能。
本文将介绍如何使用 uni-app 框架来实现一个简单的抽屉组件:DrawerWindow。文末提供完整的代码示例,让你能够轻松地在 uni-app 中实现抽屉效果。
看新机会的
技术大厂,待遇之类的给的还可以,就是偶尔有加班(放心,加班有加班费)
前后端测试捞人,多地有空位,感兴趣的可以试试~
二. 实现分析
Vue 组件的结构通常由三个主要部分组成:模板(<template>)、脚本(<script>)和样式(<style>),标准的的单文件组件(SFC)结构。
uni-app 也是如此,在这个组件中,我们也将使用 Vue 的单文件组件(SFC)结构,这意味着我们将在一个 .vue 文件中同时包含模板、脚本和样式。
接下来我们按照这个格式来简单实现一下。
-
- 模板页面 (<template>)
首先,模版页面是很简单的部分,我们需要创建一个基础的 Vue 组件,该组件包含了主页面、抽屉内容和关闭按钮三个部分。以下是组件的模板代码:
<template>
<view class="drawer-window-wrap">
<scroll-view scroll-y class="DrawerPage" :class="{ show: modalName === 'viewModal' }">
<!-- 主页面 -->
<slot></slot>
</scroll-view>
<!-- 关闭抽屉 -->
<view class="DrawerClose" :class="{ show: modalName === 'viewModal' }" @tap="hide">
<u-icon name="backspace"></u-icon>
</view>
<!-- 抽屉页面 -->
<scroll-view scroll-y class="DrawerWindow" :class="{ show: modalName === 'viewModal' }">
<slot name="drawer"></slot>
</scroll-view>
</view>
</template>
- 模板页面 (<template>)
在模板部分,我们主要定义了三个主要元素:主页面、关闭按钮和抽屉页面。每个元素都有一个class绑定,这个绑定会根据 modalName 的状态来决定是否添加 .show 类。
主页面 (<scroll-view class="DrawerPage">):
这个滚动视图代表应用的主要内容区域。
当抽屉打开时,它会被缩小并移向屏幕右侧。
提供默认插槽 <slot></slot>,允许父组件传递自定义内容到这个位置。
关闭按钮 (<view class="DrawerClose">):
位于屏幕右侧的一个透明背景层,当点击时触发 hide() 方法来关闭抽屉。
包含了一个图标 <u-icon name="backspace"></u-icon>,这里使用的是 uView UI 库中的图标组件。你可以选用其他组件库里的图标或者图片。
抽屉页面 (<scroll-view class="DrawerWindow">):
这是抽屉本身的内容区域,通常包含菜单或其他附加信息。
同样地,定义特有的插槽名称,<slot name="drawer"></slot> 允许从外部插入特定的内容。
抽屉默认是隐藏的,并且当显示时会有动画效果。
在这里,我们主要使用了 <slot> 元素来定义可以插入自定义内容的位置。modalName 属性用来控制抽屉的状态。
- 逻辑处理 (<script>)
接下来,逻辑处理其实也很简单,主要会定义打开和关闭抽屉的方法:
javascript 代码解读复制代码<script>
export default {
data() {
return {
modalName: null
}
},
methods: {
// 打开抽屉
show() {
this.modalName = 'viewModal';
},
// 关闭抽屉
hide() {
this.modalName = null;
}
}
}
</script>
数据 (data):
modalName: 用于控制抽屉状态的数据属性。当它的值为 'viewModal' 时,表示抽屉处于打开状态;否则,抽屉是关闭的。
方法 (methods):
show(): 将 modalName 设置为'viewModal',从而通过 CSS 样式控制抽屉显示。
hide(): 将 modalName 重置为 null,控制抽屉隐藏。
当调用 show() 方法时,modalName 被设置为 'viewModal',这会触发 CSS 中的 .show 类,从而显示抽屉;反之,调用 hide() 方法则会隐藏抽屉。
- 样式设计 (<style>)
在这个组件中,其实要做好的在样式部分,主要是显示抽屉的动画部分。在主页面,我们主要定义了三个主要的样式类:主页面、关闭按钮和抽屉页面。
主页面样式 (DrawerPage):
初始状态下占据整个屏幕宽度和高度。
当抽屉打开时(即有.show类),页面会缩小并移动到屏幕右侧 85%的位置,同时增加阴影效果以模拟深度。
关闭按钮样式 (DrawerClose):
默认情况下是不可见且不响应用户交互的。
当抽屉打开时,按钮变为可见并可点击,提供了一种关闭抽屉的方式。
抽屉页面样式 (DrawerWindow):
初始状态下位于屏幕左侧外侧,不显示也不响应交互。
当抽屉打开时,抽屉平滑滑入屏幕内,变得完全可见且可以与用户互动。
动画与过渡
所有的 .show 类都带有 transition: all 0.4s;,这使得任何属性的变化都会有一个 0.4 秒的平滑过渡效果。
抽屉和主页面的 transform 属性被用来控制它们的位置和大小变化。
opacity 和 pointer-events 属性确保在不需要时抽屉不会影响用户的操作。
如下代码所示,我们主要添加一些 CSS 样式来实现平滑的过渡效果以及视觉上的美观:
scss 代码解读复制代码<style lang="scss">
// 省略其他样式...
.DrawerPage.show,
.DrawerWindow.show,
.DrawerClose.show {
transition: all 0.4s;
}
.DrawerPage.show {
transform: scale(0.9, 0.9) translateX(85vw);
box-shadow: 0 0 60rpx rgba(0, 0, 0, 0.2);
}
.DrawerWindow.show {
transform: scale(1, 1) translateX(0%);
opacity: 1;
pointer-events: all;
}
.DrawerClose.show {
width: 15vw;
color: #fff;
opacity: 1;
pointer-events: all;
}
</style>
以上的这些样式确保了当抽屉显示或隐藏时有流畅的动画效果,并且在不需要的时候不会影响用户的交互。
三. 完整代码
- 完整抽屉组件,复制可使用
html 代码解读复制代码<template>
<view class="drawer-window-wrap">
<scroll-view scroll-y class="DrawerPage" :class="modalName == 'viewModal' ? 'show' : ''">
<!-- 主页面 -->
<slot></slot>
</scroll-view>
<!-- 关闭抽屉 -->
<view class="DrawerClose" :class="modalName == 'viewModal' ? 'show' : ''" @tap="hide()">
<u-icon name="backspace"></u-icon>
</view>
<!-- 抽屉页面 -->
<scroll-view scroll-y class="DrawerWindow" :class="modalName == 'viewModal' ? 'show' : ''">
<slot name="drawer"></slot>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
modalName: null
}
},
methods: {
// 打开抽屉
show() {
this.modalName = 'viewModal'
},
// 关闭抽屉
hide() {
this.modalName = null
}
}
}
</script>
<style lang="scss">
page {
width: 100vw;
overflow: hidden !important;
}
.DrawerPage {
position: fixed;
width: 100vw;
height: 100vh;
left: 0vw;
background-color: #f1f1f1;
transition: all 0.4s;
}
.DrawerPage.show {
transform: scale(0.9, 0.9);
left: 85vw;
box-shadow: 0 0 60rpx rgba(0, 0, 0, 0.2);
transform-origin: 0;
}
.DrawerWindow {
position: absolute;
width: 85vw;
height: 100vh;
left: 0;
top: 0;
transform: scale(0.9, 0.9) translateX(-100%);
opacity: 0;
pointer-events: none;
transition: all 0.4s;
background-image: linear-gradient(45deg, #1cbbb4, #2979ff) !important;
}
.DrawerWindow.show {
transform: scale(1, 1) translateX(0%);
opacity: 1;
pointer-events: all;
}
.DrawerClose {
position: absolute;
width: 40vw;
height: 100vh;
right: 0;
top: 0;
color: transparent;
padding-bottom: 50rpx;
display: flex;
align-items: flex-end;
justify-content: center;
background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 0.6));
letter-spacing: 5px;
font-size: 50rpx;
opacity: 0;
pointer-events: none;
transition: all 0.4s;
}
.DrawerClose.show {
opacity: 1;
pointer-events: all;
width: 15vw;
color: #fff;
}
</style>
- 在父组件中使用抽屉组件
在父组件中,可以通过以下简单的代码使用它,你可以继续进行丰富:
html 代码解读复制代码<template>
<drawer-window ref="drawerWindow">
<view class="main-container" @click="$refs.drawerWindow.show()">
主页面,点击打开抽屉
</view>
<view slot="drawer" class="drawer-container"> 抽屉页面 </view>
</drawer-window>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped>
.main-container,
.drawer-container {
font-weight: 700;
font-size: 20px;
text-align: center;
color: #333;
padding-top: 100px;
}
</style>
以上代码的实现效果如下图所示:
四. 小程序体验
以上的组件,来源于我独立开发的软考刷题小程序中的效果,想要体验或软考刷题的掘友可以参考以下文章,文末获取:
软考小工具重磅更新啦!最好用的软考刷题工具
五. 结语
通过以上步骤,我们已经构建了一个基本的抽屉组件。当然,你也可以根据具体的应用场景对这个组件进行进一步的定制和优化。
——转载自作者:前端梦工厂
一. 前言
我之前使用 uni-app 和 uniCloud 开发了一款软考刷题应用,在这个应用中,我使用了抽屉组件来实现一些功能,切换题库,如下图所示:
在移动应用开发中,抽屉(Drawer)是一种常见的界面设计模式,这个组件可以在需要侧边导航或者额外信息展示的地方使用。它允许用户通过侧滑的效果打开一个菜单或额外的内容区域。
这种设计不仅能够节省屏幕空间,还能提供一种直观的交互方式。
例如,在电商应用中,可以将购物车或分类列表放在抽屉里;在新闻阅读器中,可以放置频道选择等;而在有题记刷题软件中,我主要用于题库的选择功能。
本文将介绍如何使用 uni-app 框架来实现一个简单的抽屉组件:DrawerWindow。文末提供完整的代码示例,让你能够轻松地在 uni-app 中实现抽屉效果。
看新机会的
技术大厂,待遇之类的给的还可以,就是偶尔有加班(放心,加班有加班费)
前后端测试捞人,多地有空位,感兴趣的可以试试~
二. 实现分析
Vue 组件的结构通常由三个主要部分组成:模板(<template>)、脚本(<script>)和样式(<style>),标准的的单文件组件(SFC)结构。
uni-app 也是如此,在这个组件中,我们也将使用 Vue 的单文件组件(SFC)结构,这意味着我们将在一个 .vue 文件中同时包含模板、脚本和样式。
接下来我们按照这个格式来简单实现一下。
-
- 模板页面 (<template>)
首先,模版页面是很简单的部分,我们需要创建一个基础的 Vue 组件,该组件包含了主页面、抽屉内容和关闭按钮三个部分。以下是组件的模板代码:
<template>
<view class="drawer-window-wrap">
<scroll-view scroll-y class="DrawerPage" :class="{ show: modalName === 'viewModal' }">
<!-- 主页面 -->
<slot></slot>
</scroll-view>
<!-- 关闭抽屉 -->
<view class="DrawerClose" :class="{ show: modalName === 'viewModal' }" @tap="hide">
<u-icon name="backspace"></u-icon>
</view>
<!-- 抽屉页面 -->
<scroll-view scroll-y class="DrawerWindow" :class="{ show: modalName === 'viewModal' }">
<slot name="drawer"></slot>
</scroll-view>
</view>
</template>
- 模板页面 (<template>)
在模板部分,我们主要定义了三个主要元素:主页面、关闭按钮和抽屉页面。每个元素都有一个class绑定,这个绑定会根据 modalName 的状态来决定是否添加 .show 类。
主页面 (<scroll-view class="DrawerPage">):
这个滚动视图代表应用的主要内容区域。
当抽屉打开时,它会被缩小并移向屏幕右侧。
提供默认插槽 <slot></slot>,允许父组件传递自定义内容到这个位置。
关闭按钮 (<view class="DrawerClose">):
位于屏幕右侧的一个透明背景层,当点击时触发 hide() 方法来关闭抽屉。
包含了一个图标 <u-icon name="backspace"></u-icon>,这里使用的是 uView UI 库中的图标组件。你可以选用其他组件库里的图标或者图片。
抽屉页面 (<scroll-view class="DrawerWindow">):
这是抽屉本身的内容区域,通常包含菜单或其他附加信息。
同样地,定义特有的插槽名称,<slot name="drawer"></slot> 允许从外部插入特定的内容。
抽屉默认是隐藏的,并且当显示时会有动画效果。
在这里,我们主要使用了 <slot> 元素来定义可以插入自定义内容的位置。modalName 属性用来控制抽屉的状态。
- 逻辑处理 (<script>)
接下来,逻辑处理其实也很简单,主要会定义打开和关闭抽屉的方法:
javascript 代码解读复制代码<script>
export default {
data() {
return {
modalName: null
}
},
methods: {
// 打开抽屉
show() {
this.modalName = 'viewModal';
},
// 关闭抽屉
hide() {
this.modalName = null;
}
}
}
</script>
数据 (data):
modalName: 用于控制抽屉状态的数据属性。当它的值为 'viewModal' 时,表示抽屉处于打开状态;否则,抽屉是关闭的。
方法 (methods):
show(): 将 modalName 设置为'viewModal',从而通过 CSS 样式控制抽屉显示。
hide(): 将 modalName 重置为 null,控制抽屉隐藏。
当调用 show() 方法时,modalName 被设置为 'viewModal',这会触发 CSS 中的 .show 类,从而显示抽屉;反之,调用 hide() 方法则会隐藏抽屉。
- 样式设计 (<style>)
在这个组件中,其实要做好的在样式部分,主要是显示抽屉的动画部分。在主页面,我们主要定义了三个主要的样式类:主页面、关闭按钮和抽屉页面。
主页面样式 (DrawerPage):
初始状态下占据整个屏幕宽度和高度。
当抽屉打开时(即有.show类),页面会缩小并移动到屏幕右侧 85%的位置,同时增加阴影效果以模拟深度。
关闭按钮样式 (DrawerClose):
默认情况下是不可见且不响应用户交互的。
当抽屉打开时,按钮变为可见并可点击,提供了一种关闭抽屉的方式。
抽屉页面样式 (DrawerWindow):
初始状态下位于屏幕左侧外侧,不显示也不响应交互。
当抽屉打开时,抽屉平滑滑入屏幕内,变得完全可见且可以与用户互动。
动画与过渡
所有的 .show 类都带有 transition: all 0.4s;,这使得任何属性的变化都会有一个 0.4 秒的平滑过渡效果。
抽屉和主页面的 transform 属性被用来控制它们的位置和大小变化。
opacity 和 pointer-events 属性确保在不需要时抽屉不会影响用户的操作。
如下代码所示,我们主要添加一些 CSS 样式来实现平滑的过渡效果以及视觉上的美观:
scss 代码解读复制代码<style lang="scss">
// 省略其他样式...
.DrawerPage.show,
.DrawerWindow.show,
.DrawerClose.show {
transition: all 0.4s;
}
.DrawerPage.show {
transform: scale(0.9, 0.9) translateX(85vw);
box-shadow: 0 0 60rpx rgba(0, 0, 0, 0.2);
}
.DrawerWindow.show {
transform: scale(1, 1) translateX(0%);
opacity: 1;
pointer-events: all;
}
.DrawerClose.show {
width: 15vw;
color: #fff;
opacity: 1;
pointer-events: all;
}
</style>
以上的这些样式确保了当抽屉显示或隐藏时有流畅的动画效果,并且在不需要的时候不会影响用户的交互。
三. 完整代码
- 完整抽屉组件,复制可使用
html 代码解读复制代码<template>
<view class="drawer-window-wrap">
<scroll-view scroll-y class="DrawerPage" :class="modalName == 'viewModal' ? 'show' : ''">
<!-- 主页面 -->
<slot></slot>
</scroll-view>
<!-- 关闭抽屉 -->
<view class="DrawerClose" :class="modalName == 'viewModal' ? 'show' : ''" @tap="hide()">
<u-icon name="backspace"></u-icon>
</view>
<!-- 抽屉页面 -->
<scroll-view scroll-y class="DrawerWindow" :class="modalName == 'viewModal' ? 'show' : ''">
<slot name="drawer"></slot>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
modalName: null
}
},
methods: {
// 打开抽屉
show() {
this.modalName = 'viewModal'
},
// 关闭抽屉
hide() {
this.modalName = null
}
}
}
</script>
<style lang="scss">
page {
width: 100vw;
overflow: hidden !important;
}
.DrawerPage {
position: fixed;
width: 100vw;
height: 100vh;
left: 0vw;
background-color: #f1f1f1;
transition: all 0.4s;
}
.DrawerPage.show {
transform: scale(0.9, 0.9);
left: 85vw;
box-shadow: 0 0 60rpx rgba(0, 0, 0, 0.2);
transform-origin: 0;
}
.DrawerWindow {
position: absolute;
width: 85vw;
height: 100vh;
left: 0;
top: 0;
transform: scale(0.9, 0.9) translateX(-100%);
opacity: 0;
pointer-events: none;
transition: all 0.4s;
background-image: linear-gradient(45deg, #1cbbb4, #2979ff) !important;
}
.DrawerWindow.show {
transform: scale(1, 1) translateX(0%);
opacity: 1;
pointer-events: all;
}
.DrawerClose {
position: absolute;
width: 40vw;
height: 100vh;
right: 0;
top: 0;
color: transparent;
padding-bottom: 50rpx;
display: flex;
align-items: flex-end;
justify-content: center;
background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 0.6));
letter-spacing: 5px;
font-size: 50rpx;
opacity: 0;
pointer-events: none;
transition: all 0.4s;
}
.DrawerClose.show {
opacity: 1;
pointer-events: all;
width: 15vw;
color: #fff;
}
</style>
- 在父组件中使用抽屉组件
在父组件中,可以通过以下简单的代码使用它,你可以继续进行丰富:
html 代码解读复制代码<template>
<drawer-window ref="drawerWindow">
<view class="main-container" @click="$refs.drawerWindow.show()">
主页面,点击打开抽屉
</view>
<view slot="drawer" class="drawer-container"> 抽屉页面 </view>
</drawer-window>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped>
.main-container,
.drawer-container {
font-weight: 700;
font-size: 20px;
text-align: center;
color: #333;
padding-top: 100px;
}
</style>
以上代码的实现效果如下图所示:
四. 小程序体验
以上的组件,来源于我独立开发的软考刷题小程序中的效果,想要体验或软考刷题的掘友可以参考以下文章,文末获取:
软考小工具重磅更新啦!最好用的软考刷题工具
五. 结语
通过以上步骤,我们已经构建了一个基本的抽屉组件。当然,你也可以根据具体的应用场景对这个组件进行进一步的定制和优化。
——转载自作者:前端梦工厂
收起阅读 »uniapp,开发的一些插件,需要自取。有需要优化或者有bug的请发评论。后续有更新新插件会继续加上。
插件首页:https://ext.dcloud.net.cn/publisher?id=394134
1、uniapp项目,安卓权限说明,顶部蒙层(全局,不需要各个页面引入)
2、uniapp项目,拖拽组件,悬浮或浮动(按钮、广告、菜单、直播窗口等),两边停靠
3、uniapp项目,canvas合成群头像,仿微信群头像
4、uniapp项目,二次封装uni的WebSocket(SocketTask)
5、uniapp项目,数字键盘,密码键盘,带删除、小数点、确认键盘
6、uniapp项目,底部悬浮区域,固定区域
7、css原子化,类似tailwindcss
8、uniapp项目,瀑布流
9、uniapp项目,canvas生成自定义海报
插件首页:https://ext.dcloud.net.cn/publisher?id=394134
1、uniapp项目,安卓权限说明,顶部蒙层(全局,不需要各个页面引入)
2、uniapp项目,拖拽组件,悬浮或浮动(按钮、广告、菜单、直播窗口等),两边停靠
3、uniapp项目,canvas合成群头像,仿微信群头像
4、uniapp项目,二次封装uni的WebSocket(SocketTask)
5、uniapp项目,数字键盘,密码键盘,带删除、小数点、确认键盘
6、uniapp项目,底部悬浮区域,固定区域
7、css原子化,类似tailwindcss
8、uniapp项目,瀑布流
9、uniapp项目,canvas生成自定义海报























