uniapp动态路由、动态tabbar实战方案
uniapp用来开发app还是比较方便快捷的,官网教程挺细致,几乎所有问题都能找到答案。网上也有不少入门教程,腾讯课堂、b站上有好几个视频教程,感觉还可以(其实我没怎么看),比较偏实战,可以动手试一下。
本文假设阅读者已经基本掌握了uniapp的入门开发技能,如果还没有掌握uniapp,但你准备进行相关开发,赶紧从官方文档入手,再结合实战视频操作就好了,前面推荐的都不错。好了,进入本文主题——如何基于uniapp框架实现动态路由、动态tabbar。
现状分析
vue项目上有路由插件Vue Router,所有路由都是统一管理,可以统一拦截,控制下一步动作,但是在uniapp上,情况就不一样了。uniapp上没有路由插件,然后页面分为tabbar和非tabbar两种,页面跳转也有自己的一套api,最重要的路由拦截功能并不支持,所有的页面都是在page.json文件里提前配置好。
需求分析
那假设我们要在app上做一套对应着用户权限的东西,就是不同用户,根据权限配置,决定了他进来后能用哪些页面哪些按钮,甚至是能控制到tabbar这块。这个需求,就需要根据权限控制路由内容及导向,但在目前条件下是实现不了的。不过在插件市场有不少人写了路由插件,思路其实都是向web端的vue Router看齐的,能完整满足需求的只有这个路由插件。
还有很重要的一个需求就是动态tabbar,这是一个很重要内容,就是在app登录后主页下面的一栏按钮,这些tabbar基本上包括了app的主要内容,如何实现动态的tabbar,像上面提到的根据权限控制。比如说tabbar最多只能有五个,那我如何控制甲能看到5个,乙只能看到3个?这个需求在原生的uniapp上无法实现,原生的只能配置好pages,tabBar是pages的一个子项配置。不过插件市场上有人实现了tabbar的组件化,我们可以尝试下定制开发。
总结起来说需求其实就两个:
1、实现uniapp路由守卫;
2、实现动态tabbar;
第一个需求,前面提到过一些方案;第二个需求,动态tabbar,需要结合uview组件库的tabbar组件来实现。我们再分析下目前的框架、插件能力,糅合上述需求,就有这张图:
这张图里有些内容前面没有提到,比如状态管理、本地缓存,这是后面会用到的一个关键部分,下面的设计部分会提到。
方案设计
我们来捋一捋业务流程设计:
1、app输入用户名密码登录;
2、在路由守卫进行拦截,判断用户登录时的本地数据是否存在路由信息;如果没有则走第3步,如果有就走第4步;
3、调用接口获取到路由并从服务端获取路由数据;将路由数据存入本地(vuex、uniapp缓存);
4、将tabbar这一层级数据单独提出来存储,结合uview的tabbar组件实现动态tabbar;
5、在本地存一个全量的app按钮集合(除了tabbar,其他页面都是通过按钮跳转),与服务端获取的数据进行比对,得到一个按钮展示与否的配置数据集;
6、路由信息初始化后,进入用户定制化的初始页或者首页;
ok,分析得差不多了,下面介绍下具体实操步骤。
解决方案
一、实现路由守卫
路由插件推荐uni-simple-router,具体教程可以参考它的官方文档,写得比较详细了。以下是我的简单实战教程。
安装uni-simple-router插件
npm install uni-simple-router
接下来进行模块化配置,创建文件夹router,文件夹内容如下:
home文件里是所有页面的路由配置,就像这样:
const home = [
{
path: '/pages/login/login',
aliasPath:'/app/login', //对于h5端适用
name: 'login',
meta: {
title: '登录',
}
},
{
path: '/pages/index/index',
aliasPath:'/app/index', //对于h5端适用
name: 'index',
meta: {
title: '首页',
}
}]
export default home
这里必须要多说一句,由于这个插件没有动态写入功能,所以我们要实现权限管理,必须在本地配置完整的路由;而且pages.json中的内容也要完整配置,不过tabbar配置有些不同,后面会说到;
modules文件夹下的index只是一个模块读取的代码;
const files = require.context('.', false, /\.js$/)
const modules = []
files.keys().forEach(key => {
if (key === './index.js') return
const item = files(key).default
modules.push(...item)
})
export default modules
router根级目录下的index内容主要就是路由守卫:
import modules from './modules/index.js'
import Vue from 'vue'
import Router from 'uni-simple-router'
import store from '@/store/store.js'
Vue.use(Router)
//初始化
const router = new Router({
APP: {
holdTabbar: false //默认true
},
h5: {
vueRouterDev: true, //完全使用vue-router开发 默认 false
},
routes: [...modules] //路由表
});
//全局路由前置守卫
router.beforeEach((to, from, next) => {
// 首先判断是否存在路由信息
//不存在就先调用接口得到数据
//具体内容可以参照上文的方案设计内容
})
// 全局路由后置守卫
router.afterEach((to, from) => {})
export default router;
最后在app的main.js里需要这么引用:
import router from './router/index.js'
import { RouterMount } from 'uni-simple-router'
...
//v1.3.5起 H5端 你应该去除原有的app.$mount();使用路由自带的渲染方式
// #ifdef H5
RouterMount(app,'#app');
// #endif
//为了兼容小程序及app端必须这样写才有效果
// #ifndef H5
app.$mount();
// #endif
至于后面的路由用法,直接看官方文档,比较清楚,用法跟vue-router差不多。这里要特别说明的是上面代码初始化的那一块的几个配置:holdTabbar: false,vueRouterDev: true,前者表示在app端取代原生的tabbar拦截,在这个插件里拦截;后者表示在h5中完全用vue-router的api,废弃了包括此插件及uniapp的原生api,后者请慎用。
二、结合状态管理、uniapp数据缓存管理app缓存开销
这里其实没什么难度,也不给代码了,很简单。
从服务端获取的数据我可以存在状态管理里,但是vuex的数据存在内存中,容易丢失。比如说,app用一会儿,我拉到了后台,立马再点开是没问题可以用的;但如果时间太长了,不小心清了缓存,或者超过了服务端的超时限制,此时再次点开app,可能就缺失了部分数据。这个问题就要在路由守卫进行处理了,在路由跳转时就判断相关的状态数据是否存在,不存在就再进行处理。
再介绍一下uniapp的数据缓存api,更稳定,特别在app上,它不是缓存的概念,是持久化存在的,除非你调用它的清除方法。你可以利用这二者,分别存一些数据,搭配做一些控制,具体实现就自己琢磨下。比如你从后台拉回,状态管理的数据没了,但这个时间还在服务端超时范围内,那这个未超时的token数据就要存在uniapp的数据缓存中,我根据这个token再查到相关权限路由信息,给vuex赋值,再进行后续操作;如果拉回来,超时了,那就直接回到登录页。这一块,我只是提供思路,而且是成功的思路,亲测有效的。
三、实现动态tabbar
好了,能走到这一步,万里长征就走了一半了。别看下面的内容就那么一点,我把相关的资料拼起来实际上花了比上面那些更多的时间。
由于tabbar是单独配置的,原生的uniapp没有动态配置的方法。找了一圈,发现uview的tabbar组件可以实现。这块还是把步骤列一下:一步步来,是可以实现的!
1、修改pages.json配置
"tabBar": {
"list": [{
"pagePath": "pages/index/index"
},{
"pagePath": "pages/about/about"
}]
},
像这样,只留这些内容,跟原生配置比少了许多内容。
2、将tabbar信息单独存储到一个全局对象上
这一步可以存在vuex里,因为读取方便,uniapp的数据缓存读取稍微麻烦点。放在vuex里,取的时候很方便,像这样:
this.$store.state.userInfo.tabbarlist
3、在每一个tabbar页面配置tabbar组件
<template>
<view>
<view class="content">
...
</view>
<u-tabbar :list="$store.state.userInfo.tabbarlist" @change="changeTb" :inactive-color="inactiveColor" :active-color="activeColor"></u-tabbar>
</view>
</template>
模板部分格式要像上面这样,tabbar与正文内容并列;跳转代码如下,两种方式都是可以的,详细见文档
changeTb(index) {
// uni.switchTab({
// url: this.$store.state.userInfo.tabbarlist[index].pagePath
// });
this.$Router.pushTab(this.$store.state.userInfo.tabbarlist[index].pagePath)
}
需要说明的是,这种方法是把uniapp的原生tabbar给隐藏了的;上面用到的状态管理中的tabbarlist数据是一个结构参数完整的tabbar配置,但是tabbar页面可能不是完整的,由用户权限决定。
好了,本文到此已经把动态路由、动态tabbar的完整方案讲清楚了,细节部分自己顺着我的思路,根据你自己的需要,逐步完善即可,希望对你会有启发和帮助。
这是我的原文链接
uniapp用来开发app还是比较方便快捷的,官网教程挺细致,几乎所有问题都能找到答案。网上也有不少入门教程,腾讯课堂、b站上有好几个视频教程,感觉还可以(其实我没怎么看),比较偏实战,可以动手试一下。
本文假设阅读者已经基本掌握了uniapp的入门开发技能,如果还没有掌握uniapp,但你准备进行相关开发,赶紧从官方文档入手,再结合实战视频操作就好了,前面推荐的都不错。好了,进入本文主题——如何基于uniapp框架实现动态路由、动态tabbar。
现状分析
vue项目上有路由插件Vue Router,所有路由都是统一管理,可以统一拦截,控制下一步动作,但是在uniapp上,情况就不一样了。uniapp上没有路由插件,然后页面分为tabbar和非tabbar两种,页面跳转也有自己的一套api,最重要的路由拦截功能并不支持,所有的页面都是在page.json文件里提前配置好。
需求分析
那假设我们要在app上做一套对应着用户权限的东西,就是不同用户,根据权限配置,决定了他进来后能用哪些页面哪些按钮,甚至是能控制到tabbar这块。这个需求,就需要根据权限控制路由内容及导向,但在目前条件下是实现不了的。不过在插件市场有不少人写了路由插件,思路其实都是向web端的vue Router看齐的,能完整满足需求的只有这个路由插件。
还有很重要的一个需求就是动态tabbar,这是一个很重要内容,就是在app登录后主页下面的一栏按钮,这些tabbar基本上包括了app的主要内容,如何实现动态的tabbar,像上面提到的根据权限控制。比如说tabbar最多只能有五个,那我如何控制甲能看到5个,乙只能看到3个?这个需求在原生的uniapp上无法实现,原生的只能配置好pages,tabBar是pages的一个子项配置。不过插件市场上有人实现了tabbar的组件化,我们可以尝试下定制开发。
总结起来说需求其实就两个:
1、实现uniapp路由守卫;
2、实现动态tabbar;
第一个需求,前面提到过一些方案;第二个需求,动态tabbar,需要结合uview组件库的tabbar组件来实现。我们再分析下目前的框架、插件能力,糅合上述需求,就有这张图:
这张图里有些内容前面没有提到,比如状态管理、本地缓存,这是后面会用到的一个关键部分,下面的设计部分会提到。
方案设计
我们来捋一捋业务流程设计:
1、app输入用户名密码登录;
2、在路由守卫进行拦截,判断用户登录时的本地数据是否存在路由信息;如果没有则走第3步,如果有就走第4步;
3、调用接口获取到路由并从服务端获取路由数据;将路由数据存入本地(vuex、uniapp缓存);
4、将tabbar这一层级数据单独提出来存储,结合uview的tabbar组件实现动态tabbar;
5、在本地存一个全量的app按钮集合(除了tabbar,其他页面都是通过按钮跳转),与服务端获取的数据进行比对,得到一个按钮展示与否的配置数据集;
6、路由信息初始化后,进入用户定制化的初始页或者首页;
ok,分析得差不多了,下面介绍下具体实操步骤。
解决方案
一、实现路由守卫
路由插件推荐uni-simple-router,具体教程可以参考它的官方文档,写得比较详细了。以下是我的简单实战教程。
安装uni-simple-router插件
npm install uni-simple-router
接下来进行模块化配置,创建文件夹router,文件夹内容如下:
home文件里是所有页面的路由配置,就像这样:
const home = [
{
path: '/pages/login/login',
aliasPath:'/app/login', //对于h5端适用
name: 'login',
meta: {
title: '登录',
}
},
{
path: '/pages/index/index',
aliasPath:'/app/index', //对于h5端适用
name: 'index',
meta: {
title: '首页',
}
}]
export default home
这里必须要多说一句,由于这个插件没有动态写入功能,所以我们要实现权限管理,必须在本地配置完整的路由;而且pages.json中的内容也要完整配置,不过tabbar配置有些不同,后面会说到;
modules文件夹下的index只是一个模块读取的代码;
const files = require.context('.', false, /\.js$/)
const modules = []
files.keys().forEach(key => {
if (key === './index.js') return
const item = files(key).default
modules.push(...item)
})
export default modules
router根级目录下的index内容主要就是路由守卫:
import modules from './modules/index.js'
import Vue from 'vue'
import Router from 'uni-simple-router'
import store from '@/store/store.js'
Vue.use(Router)
//初始化
const router = new Router({
APP: {
holdTabbar: false //默认true
},
h5: {
vueRouterDev: true, //完全使用vue-router开发 默认 false
},
routes: [...modules] //路由表
});
//全局路由前置守卫
router.beforeEach((to, from, next) => {
// 首先判断是否存在路由信息
//不存在就先调用接口得到数据
//具体内容可以参照上文的方案设计内容
})
// 全局路由后置守卫
router.afterEach((to, from) => {})
export default router;
最后在app的main.js里需要这么引用:
import router from './router/index.js'
import { RouterMount } from 'uni-simple-router'
...
//v1.3.5起 H5端 你应该去除原有的app.$mount();使用路由自带的渲染方式
// #ifdef H5
RouterMount(app,'#app');
// #endif
//为了兼容小程序及app端必须这样写才有效果
// #ifndef H5
app.$mount();
// #endif
至于后面的路由用法,直接看官方文档,比较清楚,用法跟vue-router差不多。这里要特别说明的是上面代码初始化的那一块的几个配置:holdTabbar: false,vueRouterDev: true,前者表示在app端取代原生的tabbar拦截,在这个插件里拦截;后者表示在h5中完全用vue-router的api,废弃了包括此插件及uniapp的原生api,后者请慎用。
二、结合状态管理、uniapp数据缓存管理app缓存开销
这里其实没什么难度,也不给代码了,很简单。
从服务端获取的数据我可以存在状态管理里,但是vuex的数据存在内存中,容易丢失。比如说,app用一会儿,我拉到了后台,立马再点开是没问题可以用的;但如果时间太长了,不小心清了缓存,或者超过了服务端的超时限制,此时再次点开app,可能就缺失了部分数据。这个问题就要在路由守卫进行处理了,在路由跳转时就判断相关的状态数据是否存在,不存在就再进行处理。
再介绍一下uniapp的数据缓存api,更稳定,特别在app上,它不是缓存的概念,是持久化存在的,除非你调用它的清除方法。你可以利用这二者,分别存一些数据,搭配做一些控制,具体实现就自己琢磨下。比如你从后台拉回,状态管理的数据没了,但这个时间还在服务端超时范围内,那这个未超时的token数据就要存在uniapp的数据缓存中,我根据这个token再查到相关权限路由信息,给vuex赋值,再进行后续操作;如果拉回来,超时了,那就直接回到登录页。这一块,我只是提供思路,而且是成功的思路,亲测有效的。
三、实现动态tabbar
好了,能走到这一步,万里长征就走了一半了。别看下面的内容就那么一点,我把相关的资料拼起来实际上花了比上面那些更多的时间。
由于tabbar是单独配置的,原生的uniapp没有动态配置的方法。找了一圈,发现uview的tabbar组件可以实现。这块还是把步骤列一下:一步步来,是可以实现的!
1、修改pages.json配置
"tabBar": {
"list": [{
"pagePath": "pages/index/index"
},{
"pagePath": "pages/about/about"
}]
},
像这样,只留这些内容,跟原生配置比少了许多内容。
2、将tabbar信息单独存储到一个全局对象上
这一步可以存在vuex里,因为读取方便,uniapp的数据缓存读取稍微麻烦点。放在vuex里,取的时候很方便,像这样:
this.$store.state.userInfo.tabbarlist
3、在每一个tabbar页面配置tabbar组件
<template>
<view>
<view class="content">
...
</view>
<u-tabbar :list="$store.state.userInfo.tabbarlist" @change="changeTb" :inactive-color="inactiveColor" :active-color="activeColor"></u-tabbar>
</view>
</template>
模板部分格式要像上面这样,tabbar与正文内容并列;跳转代码如下,两种方式都是可以的,详细见文档
changeTb(index) {
// uni.switchTab({
// url: this.$store.state.userInfo.tabbarlist[index].pagePath
// });
this.$Router.pushTab(this.$store.state.userInfo.tabbarlist[index].pagePath)
}
需要说明的是,这种方法是把uniapp的原生tabbar给隐藏了的;上面用到的状态管理中的tabbarlist数据是一个结构参数完整的tabbar配置,但是tabbar页面可能不是完整的,由用户权限决定。
好了,本文到此已经把动态路由、动态tabbar的完整方案讲清楚了,细节部分自己顺着我的思路,根据你自己的需要,逐步完善即可,希望对你会有启发和帮助。
这是我的原文链接
HBuilderX 3.0.0 uniCloud目录结构调整说明
HBuilderX, 3.0.0版本,调整了uniCloud目录结构。
项目根目录下为uniCloud目录,其下有二级目录cloudfunctions 和database。database目录存放数据表schema和扩展验证函数。
为什么调整?
现有的cloudfunctions-[aliyun|tcb]目录结构在小项目下可以满足使用的要求,随着项目的越来越大,模块之间的关系越来越复杂,开发人员可能会将大部分的精力放在维护模块关系和处理代码的问题上。
那么如何让开发人员花跟多的精力在真正应该关心的核心业务上?
简单的调用和依赖关系已经不能满足复杂的业务场景,为了更好的管理模块之间的关系,使调试和维护更简单,模块解耦合的先进理念也应该深入到云函数的设计中,为此,我们推出下一阶段的uniCloud目录结构,调整了原来的cloudfunctions-[aliyun|tcb]目录结构
1. uniCloud目录结构列表详情
2. 目录迁移
如何将cloudfunctions-tcb|aliyun迁移到uniCloud-tcb|aliyun?
HBuilderX启动后,如果您的项目管理器,项目下存在cloudfunctions-tcb|aliyun目录,则会自动弹窗迁移窗口。
当然,您也可以在项目上手动操作。选择cloudfunctions-tcb|aliyun目录,右键菜单点击【迁移cloudfunctions目录】
3. 初始化云函数cloudfunctions_init.json文件调整
cloudfunctions_init.json文件内容,迁移至云函数下package.json文件
如下图所示,package.json文件,cloudfunction-config字段,即为cloudfunctions_init.json文件内容。
选中云函数,右键菜单,点击【上传部署】,会一并更新云函数初始化配置
HBuilderX, 3.0.0版本,调整了uniCloud目录结构。
项目根目录下为uniCloud目录,其下有二级目录cloudfunctions 和database。database目录存放数据表schema和扩展验证函数。
为什么调整?
现有的cloudfunctions-[aliyun|tcb]目录结构在小项目下可以满足使用的要求,随着项目的越来越大,模块之间的关系越来越复杂,开发人员可能会将大部分的精力放在维护模块关系和处理代码的问题上。
那么如何让开发人员花跟多的精力在真正应该关心的核心业务上?
简单的调用和依赖关系已经不能满足复杂的业务场景,为了更好的管理模块之间的关系,使调试和维护更简单,模块解耦合的先进理念也应该深入到云函数的设计中,为此,我们推出下一阶段的uniCloud目录结构,调整了原来的cloudfunctions-[aliyun|tcb]目录结构
1. uniCloud目录结构列表详情
2. 目录迁移
如何将cloudfunctions-tcb|aliyun迁移到uniCloud-tcb|aliyun?
HBuilderX启动后,如果您的项目管理器,项目下存在cloudfunctions-tcb|aliyun目录,则会自动弹窗迁移窗口。
当然,您也可以在项目上手动操作。选择cloudfunctions-tcb|aliyun目录,右键菜单点击【迁移cloudfunctions目录】
3. 初始化云函数cloudfunctions_init.json文件调整
cloudfunctions_init.json文件内容,迁移至云函数下package.json文件
如下图所示,package.json文件,cloudfunction-config字段,即为cloudfunctions_init.json文件内容。
选中云函数,右键菜单,点击【上传部署】,会一并更新云函数初始化配置
收起阅读 »【报BUG】阿里云云数据库DB Schema权限配置无效,请官方重视
云数据库中配置DB Schema如下
{
"bsonType": "object",
"required": [
"title"
],
"permission": {
"read": true,
"create": true,
"update": "doc.uid == auth.uid",
"delete": "doc.uid == auth.uid"
},
"properties": {
"_id": {
"description": "ID,系统自动生成"
},
"uid": {
"forceDefaultValue": {
"$env": "uid"
},
"foreignKey": "uni-id-users._id",
"permission": {
"read": true,
"create": false,
"update": false,
"delete": false
},
"description": "用户ID"
},
"updated_at": {
"forceDefaultValue": {
"$env": "now"
},
"description": "数据更新时间"
},
"ip_address": {
"permission": {
"read": false,
"write": false
},
"forceDefaultValue": {
"$env": "clientIP"
},
"description": "数据更新时间"
},
"created_at": {
"bsonType": "int",
"permission": {
"read": true,
"create": false,
"update": false,
"delete": false
},
"forceDefaultValue": {
"$env": "now"
},
"description": "数据发布时间"
},
"title": {
"bsonType": "string",
"description": "标题"
}
}
}
在前端使用clientDB查询数据,其中ip_address字段的值正常返回,并没有因为在权限中设置了read:false而不返回
这是严重的安全问题,望官方尽快修解决
顶
顶
顶
顶起
云数据库中配置DB Schema如下
{
"bsonType": "object",
"required": [
"title"
],
"permission": {
"read": true,
"create": true,
"update": "doc.uid == auth.uid",
"delete": "doc.uid == auth.uid"
},
"properties": {
"_id": {
"description": "ID,系统自动生成"
},
"uid": {
"forceDefaultValue": {
"$env": "uid"
},
"foreignKey": "uni-id-users._id",
"permission": {
"read": true,
"create": false,
"update": false,
"delete": false
},
"description": "用户ID"
},
"updated_at": {
"forceDefaultValue": {
"$env": "now"
},
"description": "数据更新时间"
},
"ip_address": {
"permission": {
"read": false,
"write": false
},
"forceDefaultValue": {
"$env": "clientIP"
},
"description": "数据更新时间"
},
"created_at": {
"bsonType": "int",
"permission": {
"read": true,
"create": false,
"update": false,
"delete": false
},
"forceDefaultValue": {
"$env": "now"
},
"description": "数据发布时间"
},
"title": {
"bsonType": "string",
"description": "标题"
}
}
}
在前端使用clientDB查询数据,其中ip_address字段的值正常返回,并没有因为在权限中设置了read:false而不返回
这是严重的安全问题,望官方尽快修解决
顶
顶
顶
顶起
建议编辑器把html及js的语义默认为html(ES6+)及javascript(ES6+),现在每次都去切换,有些麻烦
建议编辑器把html及js的语义默认为html(ES6+)及javascript(ES6+),现在每次都去切换,有些麻烦
建议编辑器把html及js的语义默认为html(ES6+)及javascript(ES6+),现在每次都去切换,有些麻烦
文件io操作中的moveTo和copyTo的坑
moveTo和copyTo的第二个参数,文档中说明的是可选,我自己实际操作,如果不给这个参数,永远都不成功,这两个参数给了就成功了。分享一下
moveTo和copyTo的第二个参数,文档中说明的是可选,我自己实际操作,如果不给这个参数,永远都不成功,这两个参数给了就成功了。分享一下
uniCloud.deleteFile相关
试了一下uniCloud.deleteFile删除的方法,发现第一种未删除成功,第二种就删除成功了。有人知道啥原因嘛
试了一下uniCloud.deleteFile删除的方法,发现第一种未删除成功,第二种就删除成功了。有人知道啥原因嘛
HBuilderX必装的插件
排名不分先后
HBuilderX主题插件
HBuilderX自定义主题辅助工具, 可以轻松定制漂亮主题。同时内置多套主题,并支持从浏览器安装主题。下载地址
eslint-js 语法校验插件
用于校验js和html中的js代码,且支持eslint 实时校验、自动修复错误。下载地址
Git源代码管理工具: easy-git
vscode源代码管理工具风格。
HBuilderX内唯一的图形化Git工具, 支持克隆、提交/更新/拉取、分支/tag管理、日志、文件对比、储藏等操作。
并且支持通过命令面板操作git相关操作。
彩虹屁老婆
虚拟程序员鼓励师老婆陪你敲代码哟。在你编程时给你爱的鼓励!下载地址
便捷翻译插件
全语种翻译(含拼音)插件 下载地址
es6代码块
常用的es6代码块 下载地址
Formator-Prettier 格式化插件
用于格式化less、sass、vue、stylus、ts、yaml代码。下载地址
compile-node-sass
compile-node-sass: scss/sass编译插件, 可以编译sass为css。下载地址
compile-less
compile-less: less插件用于less文件编译,编译less为css。下载地址
排名不分先后
HBuilderX主题插件
HBuilderX自定义主题辅助工具, 可以轻松定制漂亮主题。同时内置多套主题,并支持从浏览器安装主题。下载地址
eslint-js 语法校验插件
用于校验js和html中的js代码,且支持eslint 实时校验、自动修复错误。下载地址
Git源代码管理工具: easy-git
vscode源代码管理工具风格。
HBuilderX内唯一的图形化Git工具, 支持克隆、提交/更新/拉取、分支/tag管理、日志、文件对比、储藏等操作。
并且支持通过命令面板操作git相关操作。
彩虹屁老婆
虚拟程序员鼓励师老婆陪你敲代码哟。在你编程时给你爱的鼓励!下载地址
便捷翻译插件
全语种翻译(含拼音)插件 下载地址
es6代码块
常用的es6代码块 下载地址
Formator-Prettier 格式化插件
用于格式化less、sass、vue、stylus、ts、yaml代码。下载地址
compile-node-sass
compile-node-sass: scss/sass编译插件, 可以编译sass为css。下载地址
compile-less
compile-less: less插件用于less文件编译,编译less为css。下载地址
mac 开发h5 web浏览器 报错
There is no Internet connection
There is something wrong with the proxy server, or the address is incorrect.
Try:
Contacting the system admin
Checking the proxy address
ERR_PROXY_CONNECTION_FAILED
If you use a proxy server…
Check your proxy settings or contact your network administrator to make sure the proxy server is working. If you don't believe you should be using a proxy server: Go to Applications > System Preferences > Network > Advanced > Proxies and deselect any proxies that have been selected.
那位大咖,麻烦给我参考一下 mac代理设置
There is no Internet connection
There is something wrong with the proxy server, or the address is incorrect.
Try:
Contacting the system admin
Checking the proxy address
ERR_PROXY_CONNECTION_FAILED
If you use a proxy server…
Check your proxy settings or contact your network administrator to make sure the proxy server is working. If you don't believe you should be using a proxy server: Go to Applications > System Preferences > Network > Advanced > Proxies and deselect any proxies that have been selected.
那位大咖,麻烦给我参考一下 mac代理设置
收起阅读 »刚从apicloud转过来,分享一下看法吧
非职业码农,算是爱好
apicloud有一个优点就是更简单,文档更易阅读。
过来这边因为我没有用小程序的需求,而且对自由性要求比较高,所以没用uni-app
目前看到的就是这边api更多,但是文档写得不好(一般吧)。
很多东西不需要重新打包。例如:改为沉浸式状态栏或非沉浸式。直接更新后重启一下就行了。apicloud那边app还得重新编译一下
APP启动速度超级快,我这边的程序0.6s就可以启动完毕,那边要3s
不过apicloud的扩展性也还行,绝大多数功能都有模块供你使用
转过来的原因是因为那边吃相太难看。APP安装量大于5w,月活大于1w就需要开通商业服务。5999元以上。以后人越多还越贵。最多是2w多(大概)
当然收费并非不行,主要是页面上根本没有告诉你后续需要开通商业服务。你得经常浏览他们的论坛才能知道。真恶心人
非职业码农,算是爱好
apicloud有一个优点就是更简单,文档更易阅读。
过来这边因为我没有用小程序的需求,而且对自由性要求比较高,所以没用uni-app
目前看到的就是这边api更多,但是文档写得不好(一般吧)。
很多东西不需要重新打包。例如:改为沉浸式状态栏或非沉浸式。直接更新后重启一下就行了。apicloud那边app还得重新编译一下
APP启动速度超级快,我这边的程序0.6s就可以启动完毕,那边要3s
不过apicloud的扩展性也还行,绝大多数功能都有模块供你使用
转过来的原因是因为那边吃相太难看。APP安装量大于5w,月活大于1w就需要开通商业服务。5999元以上。以后人越多还越贵。最多是2w多(大概)
当然收费并非不行,主要是页面上根本没有告诉你后续需要开通商业服务。你得经常浏览他们的论坛才能知道。真恶心人
UniApp 中发现一个小BUG
tabbar上边做四个页面 每个页面显示标题栏 标题栏上边有个图标 图标事件弹出Drawer抽屉
如果页面里边什么都不放只放一个Drawer抽屉 先切第二个页面 弹出Drawer抽屉 再切第三个页面 弹出Drawer抽屉 然后切回第一个页面 第一个页面的tabbar不会响应onTabItemTap事件,也弹不出第一个页面的Drawer抽屉
页面里有内容就不会有这个现象
tabbar上边做四个页面 每个页面显示标题栏 标题栏上边有个图标 图标事件弹出Drawer抽屉
如果页面里边什么都不放只放一个Drawer抽屉 先切第二个页面 弹出Drawer抽屉 再切第三个页面 弹出Drawer抽屉 然后切回第一个页面 第一个页面的tabbar不会响应onTabItemTap事件,也弹不出第一个页面的Drawer抽屉
页面里有内容就不会有这个现象
Vue.js自定义PC版模态框组件|vue layer弹层
介绍
vlayer 一款基于vue.js构建的桌面端弹框组件。集合了 alert|dialog|modal|msg|notify|popover|toast|actionsheet 等多种功能于一身。
快速上手
在main.js中全局引入vlayer组件。
import VLayer from './components/vlayer';
Vue.use(VLayer);
标签式写法
<v-layer
v-model="isConfirm"
title="标题内容"
content="<div style='color:#06f;padding:15px;'>弹窗内容信息!</div>"
xclose
z-index="2002"
lockScroll="false"
resize
dragOut
:btns="[
{text: '取消', click: () => isConfirm=false},
{text: '确定', style: 'color:#f90;', click: handleFn},
]"
/>
函数式写法
let $el = this.$vlayer({
title: '标题内容',
content: '<div style='color:#06f;padding:15px;'>弹窗内容信息!</div>',
xclose: true,
zIndex: 2002,
lockScroll: false,
resize: true,
dragOut: true,
btns: [
{text: '取消', click: () => { $el.close(); }},
{text: '确定', click: () => this.handleFn()},
]
});
效果预览
配置参数
vlayer默认支持30+种参数任意搭配。
@@默认参数
v-model 当前组件是否显示
title 标题
content 内容(支持自定义插槽内容)
type 弹窗类型(toast | footer | actionsheet | android/ios | contextmenu | drawer | iframe | message/notify/popover)
layerStyle 自定义弹窗样式
icon toast图标(loading | success | fail)
shade 是否显示遮罩层
shadeClose 是否点击遮罩时关闭弹窗
lockScroll 是否弹窗出现时将 body 滚动锁定
opacity 遮罩层透明度
xclose 是否显示关闭图标
xposition 关闭图标位置(left | right | top | bottom)
xcolor 关闭图标颜色
anim 弹窗动画(scaleIn | fadeIn | footer | fadeInUp | fadeInDown | fadeInLeft | fadeInRight)
position 弹出位置(auto | ['100px','50px'] | t | r | b | l | lt | rt | lb | rb)
drawer 抽屉弹窗(top | right | bottom | left)
follow 跟随元素定位弹窗(支持元素.kk #kk 或 [e.clientX, e.clientY])
time 弹窗自动关闭秒数(1、2、3)
zIndex 弹窗层叠(默认8080)
topmost 置顶当前窗口(默认false)
area 弹窗宽高(默认auto)设置宽度area: '300px' 设置高度area:['', '200px'] 设置宽高area:['350px', '150px']
maxWidth 弹窗最大宽度(只有当area:'auto'时,maxWidth的设定才有效)
maximize 是否显示最大化按钮(默认false)
fullscreen 全屏弹窗(默认false)
fixed 弹窗是否固定
drag 拖拽元素(可定义选择器drag:'.xxx' | 禁止拖拽drag:false)
dragOut 是否允许拖拽到窗口外(默认false)
resize 是否允许拉伸尺寸(默认false)
btns 弹窗按钮(参数:text|style|disabled|click)
------------------------------------------
@@组件式事件
open 打开弹出层时触发(@open="xxx")
close 关闭弹出层时触发(@close="xxx")
------------------------------------------
@@函数式事件
onOpen 打开弹窗回调
onClose 关闭弹窗回调
vlayer.vue模板
<template>
<div v-show="opened" class="vui__layer" :class="{'vui__layer-closed': closeCls}" :id="vlayerId">
<div v-if="JSON.parse(shade)" class="vlayer__overlay" @click="shadeClicked" :style="{opacity}"></div>
<div class="vlayer__wrap" :class="[''+anim, type&&'popui__'+type, drawer&&'popui'+drawer, xclose&&'vlayer-closable', tipArrow]" :style="layerStyle">
<div v-if="title" class="vlayer__wrap-tit" v-html="title"></div>
<div v-if="type=='toast'&&icon" class="vlayer__toast-icon" :class="['vlayer'+icon]" v-html="toastIcon[icon]"></div>
<div class="vlayer__wrap-cntbox">
<template v-if="$slots.content">
<div class="vlayer__wrap-cnt"><slot name="content" /></div>
</template>
<template v-else>
<template v-if="content">
<iframe v-if="type=='iframe'" scrolling="auto" allowtransparency="true" frameborder="0" :src="content"></iframe>
<!-- message|notify|popover -->
<div v-else-if="type=='message' || type=='notify' || type=='popover'" class="vlayer__wrap-cnt">
<i v-if="icon" class="vlayer-msg__icon" :class="icon" v-html="messageIcon[icon]"></i>
<div class="vlayer-msg__group"><div v-if="title" class="vlayer-msg__title" v-html="title"></div><div class="vlayer-msg__content" v-html="content"></div></div>
</div><div v-else class="vlayer__wrap-cnt" v-html="content"></div>
</template>
</template>
<slot />
</div>
<div v-if="btns" class="vlayer__wrap-btns">
<span v-for="(btn,index) in btns" :key="index" class="btn" :class="{'btn-disabled': btn.disabled}" :style="btn.style" v-html="btn.text"></span>
</div>
<span v-if="xclose" class="vlayer__xclose" :class="!maximize&&xposition" :style="{'color': xcolor}" @click="close"></span>
<span v-if="maximize" class="vlayer__maximize"></span>
<span v-if="resize" class="vlayer__resize"></span>
</div>
<!-- 修复拖拽卡顿 -->
<div class="vlayer__dragfix"></div>
</div>
</template>
默认标题是拖拽区域,当然也可以自定义拖拽元素,只需设置 drag: '#xxx' 或者设置drag: false 来禁止弹窗拖拽功能。
当设置 dragOut: true 窗体可以拖拽到浏览器外部。
当使用popover弹窗,需要传入follow: '#xxxx' 定位元素。
另外还支持自定义弹窗显示位置,只需配置position即可。
<!-- 自定义弹窗位置 -->
<v-layer v-model="showPosition" xclose maximize drag=".dragImg" :position="rb">
<img class="dragImg" src="xxx.jpg" />
</v-layer>
设置fullscreen: true会全屏显示弹窗。
okay,基于vue.js开发pc端弹窗插件就分享到这里。希望对大家有所帮助哈!✍✍
链接:https://juejin.im/post/6890442763041669127/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
介绍
vlayer 一款基于vue.js构建的桌面端弹框组件。集合了 alert|dialog|modal|msg|notify|popover|toast|actionsheet 等多种功能于一身。
快速上手
在main.js中全局引入vlayer组件。
import VLayer from './components/vlayer';
Vue.use(VLayer);
标签式写法
<v-layer
v-model="isConfirm"
title="标题内容"
content="<div style='color:#06f;padding:15px;'>弹窗内容信息!</div>"
xclose
z-index="2002"
lockScroll="false"
resize
dragOut
:btns="[
{text: '取消', click: () => isConfirm=false},
{text: '确定', style: 'color:#f90;', click: handleFn},
]"
/>
函数式写法
let $el = this.$vlayer({
title: '标题内容',
content: '<div style='color:#06f;padding:15px;'>弹窗内容信息!</div>',
xclose: true,
zIndex: 2002,
lockScroll: false,
resize: true,
dragOut: true,
btns: [
{text: '取消', click: () => { $el.close(); }},
{text: '确定', click: () => this.handleFn()},
]
});
效果预览
配置参数
vlayer默认支持30+种参数任意搭配。
@@默认参数
v-model 当前组件是否显示
title 标题
content 内容(支持自定义插槽内容)
type 弹窗类型(toast | footer | actionsheet | android/ios | contextmenu | drawer | iframe | message/notify/popover)
layerStyle 自定义弹窗样式
icon toast图标(loading | success | fail)
shade 是否显示遮罩层
shadeClose 是否点击遮罩时关闭弹窗
lockScroll 是否弹窗出现时将 body 滚动锁定
opacity 遮罩层透明度
xclose 是否显示关闭图标
xposition 关闭图标位置(left | right | top | bottom)
xcolor 关闭图标颜色
anim 弹窗动画(scaleIn | fadeIn | footer | fadeInUp | fadeInDown | fadeInLeft | fadeInRight)
position 弹出位置(auto | ['100px','50px'] | t | r | b | l | lt | rt | lb | rb)
drawer 抽屉弹窗(top | right | bottom | left)
follow 跟随元素定位弹窗(支持元素.kk #kk 或 [e.clientX, e.clientY])
time 弹窗自动关闭秒数(1、2、3)
zIndex 弹窗层叠(默认8080)
topmost 置顶当前窗口(默认false)
area 弹窗宽高(默认auto)设置宽度area: '300px' 设置高度area:['', '200px'] 设置宽高area:['350px', '150px']
maxWidth 弹窗最大宽度(只有当area:'auto'时,maxWidth的设定才有效)
maximize 是否显示最大化按钮(默认false)
fullscreen 全屏弹窗(默认false)
fixed 弹窗是否固定
drag 拖拽元素(可定义选择器drag:'.xxx' | 禁止拖拽drag:false)
dragOut 是否允许拖拽到窗口外(默认false)
resize 是否允许拉伸尺寸(默认false)
btns 弹窗按钮(参数:text|style|disabled|click)
------------------------------------------
@@组件式事件
open 打开弹出层时触发(@open="xxx")
close 关闭弹出层时触发(@close="xxx")
------------------------------------------
@@函数式事件
onOpen 打开弹窗回调
onClose 关闭弹窗回调
vlayer.vue模板
<template>
<div v-show="opened" class="vui__layer" :class="{'vui__layer-closed': closeCls}" :id="vlayerId">
<div v-if="JSON.parse(shade)" class="vlayer__overlay" @click="shadeClicked" :style="{opacity}"></div>
<div class="vlayer__wrap" :class="[''+anim, type&&'popui__'+type, drawer&&'popui'+drawer, xclose&&'vlayer-closable', tipArrow]" :style="layerStyle">
<div v-if="title" class="vlayer__wrap-tit" v-html="title"></div>
<div v-if="type=='toast'&&icon" class="vlayer__toast-icon" :class="['vlayer'+icon]" v-html="toastIcon[icon]"></div>
<div class="vlayer__wrap-cntbox">
<template v-if="$slots.content">
<div class="vlayer__wrap-cnt"><slot name="content" /></div>
</template>
<template v-else>
<template v-if="content">
<iframe v-if="type=='iframe'" scrolling="auto" allowtransparency="true" frameborder="0" :src="content"></iframe>
<!-- message|notify|popover -->
<div v-else-if="type=='message' || type=='notify' || type=='popover'" class="vlayer__wrap-cnt">
<i v-if="icon" class="vlayer-msg__icon" :class="icon" v-html="messageIcon[icon]"></i>
<div class="vlayer-msg__group"><div v-if="title" class="vlayer-msg__title" v-html="title"></div><div class="vlayer-msg__content" v-html="content"></div></div>
</div><div v-else class="vlayer__wrap-cnt" v-html="content"></div>
</template>
</template>
<slot />
</div>
<div v-if="btns" class="vlayer__wrap-btns">
<span v-for="(btn,index) in btns" :key="index" class="btn" :class="{'btn-disabled': btn.disabled}" :style="btn.style" v-html="btn.text"></span>
</div>
<span v-if="xclose" class="vlayer__xclose" :class="!maximize&&xposition" :style="{'color': xcolor}" @click="close"></span>
<span v-if="maximize" class="vlayer__maximize"></span>
<span v-if="resize" class="vlayer__resize"></span>
</div>
<!-- 修复拖拽卡顿 -->
<div class="vlayer__dragfix"></div>
</div>
</template>
默认标题是拖拽区域,当然也可以自定义拖拽元素,只需设置 drag: '#xxx' 或者设置drag: false 来禁止弹窗拖拽功能。
当设置 dragOut: true 窗体可以拖拽到浏览器外部。
当使用popover弹窗,需要传入follow: '#xxxx' 定位元素。
另外还支持自定义弹窗显示位置,只需配置position即可。
<!-- 自定义弹窗位置 -->
<v-layer v-model="showPosition" xclose maximize drag=".dragImg" :position="rb">
<img class="dragImg" src="xxx.jpg" />
</v-layer>
设置fullscreen: true会全屏显示弹窗。
okay,基于vue.js开发pc端弹窗插件就分享到这里。希望对大家有所帮助哈!✍✍
链接:https://juejin.im/post/6890442763041669127/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
从uniapp的webview跳回APP的方法
今天找一个网站:https://www.jianshu.com/p/163b1cdd664d 分享出来以后查看
今天找一个网站:https://www.jianshu.com/p/163b1cdd664d 分享出来以后查看






