HBuilderX Git 使用技巧
easy-git, 是基于HBuilderX API开发的可视化图形Git插件,界面参考vscode源代码管理器。包含源代码管理器文件视图、日志视图、分支/tag视图、文件对比视图,且支持命令面板操作。
easy-git安装:下载地址
下面将介绍HBuilderX easy-git插件技巧。
技巧1. 查看当前文件在另一个分支的内容
通常,查看文件在另一个分支的内容,需要切换分支,或打开终端使用命令行进行查看。费时费力,还需要记忆各种命令。
easy-git,在编辑器打开文件,右键菜单【查看当前文件在另一个分支的内容】
技巧2. 显示当前行代码最后一次提交信息
在大项目工作时,大家问的最多的问题是“这一行到底是谁写的”。easy-git插件,提供了基于git blame显示某行最后提交者的功能。
打开文件,将光标置于要查看的行上,右键菜单【easy-git】【blame - 显示当前行代码最后一次提交信息】
技巧3. 用提交信息标注文件中的每一行
作为程序媛,难免会有锅砸在头上,这个时候可以使用annotate,查看当前文件每一行代码修改时间及修改人。
打开文件,将光标置于要查看的行上,右键菜单【easy-git】【annotate - 用提交信息标注文件中的每一行】
技巧4. git reflog
git reflog, 又被称为救命神器。
开发过程中,难免误操作,导致提交丢失。这个时候,可以利用reflog找到commitid,然后重置到相应提交。
技巧5. 命令面板
命令面板是一个非常特殊的 UI 组件,如果您用过 VSCode 或者 Sublime 之类的编辑器,那么您就会离不开它。
easy-git,提供了git 命令面板,可以方便快捷的操作git。
技巧6. 搜索github仓库,并克隆
通常,克隆仓库之前,您需要知道知道git仓库地址。
easy-git,支持在克隆窗口,输入关键字回车搜索,在Github搜索结果中,选择相应仓库进行克隆,克隆更便捷。
技巧7. 创建远程仓库
如果您使用的是github、gitee,创建远程仓库时,需要打开浏览器,打开相应页面,创建费事费力。创建完之后,还需要手动克隆,更是麻烦。
easy-git,支持在HBuilderX内,打开相应窗口,直接创建远程操作,创建完成之后,直接克隆到本地。
技巧8. 对比两个分支提交
多人协作开发时,通常会有好几个分支,比如master、dev、test等。每个人在部分的分支上开发,怎么比较分支有哪些不通呢?
easy-git,支持查看两个分支不通之处。具体见截图。
easy-git, 是基于HBuilderX API开发的可视化图形Git插件,界面参考vscode源代码管理器。包含源代码管理器文件视图、日志视图、分支/tag视图、文件对比视图,且支持命令面板操作。
easy-git安装:下载地址
下面将介绍HBuilderX easy-git插件技巧。
技巧1. 查看当前文件在另一个分支的内容
通常,查看文件在另一个分支的内容,需要切换分支,或打开终端使用命令行进行查看。费时费力,还需要记忆各种命令。
easy-git,在编辑器打开文件,右键菜单【查看当前文件在另一个分支的内容】
技巧2. 显示当前行代码最后一次提交信息
在大项目工作时,大家问的最多的问题是“这一行到底是谁写的”。easy-git插件,提供了基于git blame显示某行最后提交者的功能。
打开文件,将光标置于要查看的行上,右键菜单【easy-git】【blame - 显示当前行代码最后一次提交信息】
技巧3. 用提交信息标注文件中的每一行
作为程序媛,难免会有锅砸在头上,这个时候可以使用annotate,查看当前文件每一行代码修改时间及修改人。
打开文件,将光标置于要查看的行上,右键菜单【easy-git】【annotate - 用提交信息标注文件中的每一行】
技巧4. git reflog
git reflog, 又被称为救命神器。
开发过程中,难免误操作,导致提交丢失。这个时候,可以利用reflog找到commitid,然后重置到相应提交。
技巧5. 命令面板
命令面板是一个非常特殊的 UI 组件,如果您用过 VSCode 或者 Sublime 之类的编辑器,那么您就会离不开它。
easy-git,提供了git 命令面板,可以方便快捷的操作git。
技巧6. 搜索github仓库,并克隆
通常,克隆仓库之前,您需要知道知道git仓库地址。
easy-git,支持在克隆窗口,输入关键字回车搜索,在Github搜索结果中,选择相应仓库进行克隆,克隆更便捷。
技巧7. 创建远程仓库
如果您使用的是github、gitee,创建远程仓库时,需要打开浏览器,打开相应页面,创建费事费力。创建完之后,还需要手动克隆,更是麻烦。
easy-git,支持在HBuilderX内,打开相应窗口,直接创建远程操作,创建完成之后,直接克隆到本地。
技巧8. 对比两个分支提交
多人协作开发时,通常会有好几个分支,比如master、dev、test等。每个人在部分的分支上开发,怎么比较分支有哪些不通呢?
easy-git,支持查看两个分支不通之处。具体见截图。
收起阅读 »vite.js+vue3+electron12.0.4超清爽UI界面前端中后台管理系统
上次有给大家分享一个Electron跨端仿抖音短视频项目,这次带来最新研发的vite.js+electron开发vue3中后台管理系统。
vite2-vue3-electronAdmin:一套基于electron+vite.js和element-plus组件库开发的客户端后台管理系统EXE。使用了最新的vue3全家桶技术,内置了 Vue-i18n 国际化解决方案,支持PC桌面端和平板自适应布局。
electron12 vite2.x仿制抖音短视频|直播聊天
基于最新的前端技术栈vite2+vue3全家桶+electron12+element-plus+echarts5开发而来。
技术栈
- 编码器:VScode
- 构建工具:Vitejs
- vue3全家桶:Vue3.0+Vuex4+Vue-router@4
- 跨端框架:Electron^12.0.4
- 打包工具:vue-cli-plugin-electron-builder
- UI组件库:element-plus^1.0.2 (饿了么vue3组件库)
- 表格拖拽:Sortablejs^1.13
- 图表组件:Echarts^5.1
- 国际化:vue-i18n^9.1
- 模拟请求:mockjs^1.1
特性
- 使用最新前端技术栈开发
- 支持桌面端及平板响应式布局
- 支持组件式+指令式两种权限认证方式
- 支持中英文/繁体国际化方案
- 支持表格拖拽排序、全屏表格、树形表格等功能
- 支持个性化换肤
项目结构
main.js配置
/**
* 渲染进程主入口
* @author XiaoYan
*/
import { createApp } from 'vue'
import App from './App.vue'
import Router from './router'
import Store from './store'
// 引入公共配置
import gPlugins from './plugins'
import { winCfg, loadWin } from './windows/actions'
loadWin().then(config => {
winCfg.window = config
createApp(App)
.use(Router)
.use(Store)
.use(gPlugins)
.mount('#app')
})
vue-router路由配置
项目中的路由采用了结构化分层加载,分为验证路由authRoutes.js和主模块路由mainRoutes.js两大部分。
/**
* 路由配置 Router util
* @author XiaoYan
*/
import { createRouter, createWebHashHistory } from "vue-router"
import { ElLoading } from "element-plus"
import { loginWin } from "@/windows/actions"
import store from '@/store'
// 导入公共模板/路由配置
import mainLayout from "@/layouts/main"
import authLayout from "@/layouts/auth"
import mainRoutes from "@/layouts/main/routes.js"
import authRoutes from "@/layouts/auth/routes.js"
const RoutesLs = [
// 主页面模块
{
path: '/',
redirect: '/home/index',
component: mainLayout,
children: mainRoutes,
},
// 验证模块
{
path: '/auth',
redirect: '/auth/login',
component: authLayout,
children: authRoutes,
},
// 错误模块
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404.vue'),
meta: {
title: 'app__global-page-notfound',
}
}
]
const router = createRouter({
history: createWebHashHistory(),
routes: RoutesLs,
})
let loadingIns
router.beforeEach((to, from, next) => {
// 开启加载提示
loadingIns = ElLoading.service({
lock: true,
text: 'Loading...',
spinner: 'el-icon-loading',
background: 'rgba(19, 209, 122, .1)'
})
// 判断当前路由状态
const isLogined = store.state.isLogin
if(to.meta.auth) {
if(isLogined) {
next()
}else {
loginWin()
loadingIns.close()
}
}else {
next()
}
})
router.afterEach(() => {
loadingIns.close()
})
electron-vue3自定义仿Mac导航栏
项目中顶部导航条采用的是mac导航条风格,关闭/最小化/最大化按钮在左侧。
<!-- //仿Mac导航条 -->
<template>
<WinBar zIndex="1000">
<template #wbtn>
<MsgMenu />
<Lang />
<a class="wbtn" @click="handleSkinWin"><i class="iconfont icon-huanfu"></i></a>
<Setting />
<a class="wbtn" @click="handleRefresh"><i class="iconfont el-icon-refresh"></i></a>
<a class="wbtn" :class="{'on': isAlwaysOnTop}" :title="isAlwaysOnTop ? '取消置顶' : '置顶'" @click="handleAlwaysTop"><i class="iconfont icon-ding"></i></a>
<Avatar @logout="handleLogout" />
</template>
</WinBar>
</template>
vue-i18n国际化方案
新建一个locale目录用来存放项目中语言文件。
/**
* @desc vue-i18n国际化配置文件
* @Time andy by 2021-05
* @Author Q:282310962 wx:xy190310
*/
import { createI18n } from 'vue-i18n'
import Storage from '@/utils/storage'
// 默认设置
export const langKey = 'lang'
export const langVal = 'zh-CN'
/**
* 引入element-plus国际化包
*/
import enUS from 'element-plus/lib/locale/lang/en'
import zhCN from 'element-plus/lib/locale/lang/zh-cn'
import zhTW from 'element-plus/lib/locale/lang/zh-tw'
export const ElPlusLang = {
'en-US': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW
}
/**
* 初始化多语言
*/
export const $messages = importLang()
export const $lang = getLang()
const i18n = createI18n({
legacy: false,
locale: $lang,
messages: $messages
})
/**
* 自动导入语言配置
*/
export function importLang() {
const localeModule = {}
try {
// 导入 @/layouts 文件夹下包含子目录locale中的xxx.js文件
const layoutsCtx = require.context('@/layouts', true, /[/\\]locale[/\\]([a-z]{2})-?([A-Z]{2})?\.js$/)
layoutsCtx.keys().map(path => {
const pathCtx = layoutsCtx(path)
if(pathCtx.default) {
const pathName = path.replace(/(.*\/)*([^.]+).*/ig, '$2')
if(localeModule[pathName]) {
localeModule[pathName] = {
...localeModule[pathName], ...pathCtx.default
}
}else {
localeModule[pathName] = pathCtx.default
}
}
})
} catch (error) {
console.log(error)
}
return localeModule
}
/**
* 存储设置语言
* @param lang 语言类型 zh-CN | zh-TW | en-US
*/
export function setLang(lang, reload = false) {
if(getLang() !== lang) {
Storage.set(langKey, lang || '')
// 设置全局语言
i18n.global.locale.value = lang
if(reload) {
window.location.reload()
}
}
}
/**
* 获取语言
*/
export function getLang() {
const lang = Storage.get(langKey)
return lang || langVal
}
vite2+electron主模板布局
项目整体分为顶部导航条、侧边栏、路由菜单、右侧上面包屑导航、右侧下主体内容。
<!-- //Main主模块模板 -->
<template>
<div class="vadmin__wrapper" :style="{'--themeSkin': store.state.skin}">
<div v-if="!route.meta.isNewin" class="vadmin__layouts-main flexbox flex-col">
<!-- //顶部导航 -->
<div class="layout__topbar">
<TopNav />
</div>
<div class="layout__workpanel flex1 flexbox">
<!-- //侧边栏 -->
<div v-show="rootRouteEnable" class="panel__leftlayer">
<SideMenu :routes="mainRoutes" :rootRoute="rootRoute" />
</div>
<!-- //中间栏 -->
<div class="panel__middlelayer" :class="{'collapsed': collapsed}">
<RouteMenu
:routes="getAllRoutes"
:rootRoute="rootRoute"
:defaultActive="defaultActive"
:rootRouteEnable="rootRouteEnable"
/>
</div>
<!-- //右边栏 -->
<div class="panel__rightlayer flex1 flexbox flex-col">
<!-- 面包屑导航 -->
<BreadCrumb />
<!-- 主内容区 -->
<v3-scroll autohide>
<div class="lay__container">
<!-- //路由权限控制 -->
<permission :roles="route.meta.roles">
<template #tooltips>
<Forbidden />
</template>
<router-view></router-view>
</permission>
</div>
</v3-scroll>
</div>
</div>
</div>
<router-view v-else class="vadmin__layouts-main flexbox flex-col"></router-view>
</div>
</template>
Vue3图表化Hook
项目中多个地方需要使用到图表功能,于是就封装了一个图表hook函数。
/**
* 封装图表Hook
* @author XiaoYan
*/
import { onMounted, onBeforeUnmount, ref } from "vue"
import * as echarts from "echarts"
import elementResizeDetectorMaker from "element-resize-detector"
import utils from "@/utils"
export default function useChart(refs, options) {
let chartInst
let chartRef = ref(null)
let erd = elementResizeDetectorMaker()
const handleResize = utils.debounce(() => {
chartInst.resize()
}, 100)
onMounted(() => {
if(refs.value) {
chartInst = echarts.init(refs.value)
chartInst.setOption(options)
chartRef.value = chartInst
}
// window.addEventListener('resize', handleResize)
erd.listenTo(refs.value, handleResize)
})
onBeforeUnmount(() => {
chartInst.dispose()
// window.removeEventListener('resize', handleResize)
erd.removeListener(refs.value, handleResize)
})
return chartRef
}
Okay,基于vite.js+vue3+electron开发管理后台就分享到这里。希望对小伙伴们有些帮助!
链接:https://juejin.cn/post/6963310387945013261/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
上次有给大家分享一个Electron跨端仿抖音短视频项目,这次带来最新研发的vite.js+electron开发vue3中后台管理系统。
vite2-vue3-electronAdmin:一套基于electron+vite.js和element-plus组件库开发的客户端后台管理系统EXE。使用了最新的vue3全家桶技术,内置了 Vue-i18n 国际化解决方案,支持PC桌面端和平板自适应布局。
electron12 vite2.x仿制抖音短视频|直播聊天
基于最新的前端技术栈vite2+vue3全家桶+electron12+element-plus+echarts5开发而来。
技术栈
- 编码器:VScode
- 构建工具:Vitejs
- vue3全家桶:Vue3.0+Vuex4+Vue-router@4
- 跨端框架:Electron^12.0.4
- 打包工具:vue-cli-plugin-electron-builder
- UI组件库:element-plus^1.0.2 (饿了么vue3组件库)
- 表格拖拽:Sortablejs^1.13
- 图表组件:Echarts^5.1
- 国际化:vue-i18n^9.1
- 模拟请求:mockjs^1.1
特性
- 使用最新前端技术栈开发
- 支持桌面端及平板响应式布局
- 支持组件式+指令式两种权限认证方式
- 支持中英文/繁体国际化方案
- 支持表格拖拽排序、全屏表格、树形表格等功能
- 支持个性化换肤
项目结构
main.js配置
/**
* 渲染进程主入口
* @author XiaoYan
*/
import { createApp } from 'vue'
import App from './App.vue'
import Router from './router'
import Store from './store'
// 引入公共配置
import gPlugins from './plugins'
import { winCfg, loadWin } from './windows/actions'
loadWin().then(config => {
winCfg.window = config
createApp(App)
.use(Router)
.use(Store)
.use(gPlugins)
.mount('#app')
})
vue-router路由配置
项目中的路由采用了结构化分层加载,分为验证路由authRoutes.js和主模块路由mainRoutes.js两大部分。
/**
* 路由配置 Router util
* @author XiaoYan
*/
import { createRouter, createWebHashHistory } from "vue-router"
import { ElLoading } from "element-plus"
import { loginWin } from "@/windows/actions"
import store from '@/store'
// 导入公共模板/路由配置
import mainLayout from "@/layouts/main"
import authLayout from "@/layouts/auth"
import mainRoutes from "@/layouts/main/routes.js"
import authRoutes from "@/layouts/auth/routes.js"
const RoutesLs = [
// 主页面模块
{
path: '/',
redirect: '/home/index',
component: mainLayout,
children: mainRoutes,
},
// 验证模块
{
path: '/auth',
redirect: '/auth/login',
component: authLayout,
children: authRoutes,
},
// 错误模块
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404.vue'),
meta: {
title: 'app__global-page-notfound',
}
}
]
const router = createRouter({
history: createWebHashHistory(),
routes: RoutesLs,
})
let loadingIns
router.beforeEach((to, from, next) => {
// 开启加载提示
loadingIns = ElLoading.service({
lock: true,
text: 'Loading...',
spinner: 'el-icon-loading',
background: 'rgba(19, 209, 122, .1)'
})
// 判断当前路由状态
const isLogined = store.state.isLogin
if(to.meta.auth) {
if(isLogined) {
next()
}else {
loginWin()
loadingIns.close()
}
}else {
next()
}
})
router.afterEach(() => {
loadingIns.close()
})
electron-vue3自定义仿Mac导航栏
项目中顶部导航条采用的是mac导航条风格,关闭/最小化/最大化按钮在左侧。
<!-- //仿Mac导航条 -->
<template>
<WinBar zIndex="1000">
<template #wbtn>
<MsgMenu />
<Lang />
<a class="wbtn" @click="handleSkinWin"><i class="iconfont icon-huanfu"></i></a>
<Setting />
<a class="wbtn" @click="handleRefresh"><i class="iconfont el-icon-refresh"></i></a>
<a class="wbtn" :class="{'on': isAlwaysOnTop}" :title="isAlwaysOnTop ? '取消置顶' : '置顶'" @click="handleAlwaysTop"><i class="iconfont icon-ding"></i></a>
<Avatar @logout="handleLogout" />
</template>
</WinBar>
</template>
vue-i18n国际化方案
新建一个locale目录用来存放项目中语言文件。
/**
* @desc vue-i18n国际化配置文件
* @Time andy by 2021-05
* @Author Q:282310962 wx:xy190310
*/
import { createI18n } from 'vue-i18n'
import Storage from '@/utils/storage'
// 默认设置
export const langKey = 'lang'
export const langVal = 'zh-CN'
/**
* 引入element-plus国际化包
*/
import enUS from 'element-plus/lib/locale/lang/en'
import zhCN from 'element-plus/lib/locale/lang/zh-cn'
import zhTW from 'element-plus/lib/locale/lang/zh-tw'
export const ElPlusLang = {
'en-US': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW
}
/**
* 初始化多语言
*/
export const $messages = importLang()
export const $lang = getLang()
const i18n = createI18n({
legacy: false,
locale: $lang,
messages: $messages
})
/**
* 自动导入语言配置
*/
export function importLang() {
const localeModule = {}
try {
// 导入 @/layouts 文件夹下包含子目录locale中的xxx.js文件
const layoutsCtx = require.context('@/layouts', true, /[/\\]locale[/\\]([a-z]{2})-?([A-Z]{2})?\.js$/)
layoutsCtx.keys().map(path => {
const pathCtx = layoutsCtx(path)
if(pathCtx.default) {
const pathName = path.replace(/(.*\/)*([^.]+).*/ig, '$2')
if(localeModule[pathName]) {
localeModule[pathName] = {
...localeModule[pathName], ...pathCtx.default
}
}else {
localeModule[pathName] = pathCtx.default
}
}
})
} catch (error) {
console.log(error)
}
return localeModule
}
/**
* 存储设置语言
* @param lang 语言类型 zh-CN | zh-TW | en-US
*/
export function setLang(lang, reload = false) {
if(getLang() !== lang) {
Storage.set(langKey, lang || '')
// 设置全局语言
i18n.global.locale.value = lang
if(reload) {
window.location.reload()
}
}
}
/**
* 获取语言
*/
export function getLang() {
const lang = Storage.get(langKey)
return lang || langVal
}
vite2+electron主模板布局
项目整体分为顶部导航条、侧边栏、路由菜单、右侧上面包屑导航、右侧下主体内容。
<!-- //Main主模块模板 -->
<template>
<div class="vadmin__wrapper" :style="{'--themeSkin': store.state.skin}">
<div v-if="!route.meta.isNewin" class="vadmin__layouts-main flexbox flex-col">
<!-- //顶部导航 -->
<div class="layout__topbar">
<TopNav />
</div>
<div class="layout__workpanel flex1 flexbox">
<!-- //侧边栏 -->
<div v-show="rootRouteEnable" class="panel__leftlayer">
<SideMenu :routes="mainRoutes" :rootRoute="rootRoute" />
</div>
<!-- //中间栏 -->
<div class="panel__middlelayer" :class="{'collapsed': collapsed}">
<RouteMenu
:routes="getAllRoutes"
:rootRoute="rootRoute"
:defaultActive="defaultActive"
:rootRouteEnable="rootRouteEnable"
/>
</div>
<!-- //右边栏 -->
<div class="panel__rightlayer flex1 flexbox flex-col">
<!-- 面包屑导航 -->
<BreadCrumb />
<!-- 主内容区 -->
<v3-scroll autohide>
<div class="lay__container">
<!-- //路由权限控制 -->
<permission :roles="route.meta.roles">
<template #tooltips>
<Forbidden />
</template>
<router-view></router-view>
</permission>
</div>
</v3-scroll>
</div>
</div>
</div>
<router-view v-else class="vadmin__layouts-main flexbox flex-col"></router-view>
</div>
</template>
Vue3图表化Hook
项目中多个地方需要使用到图表功能,于是就封装了一个图表hook函数。
/**
* 封装图表Hook
* @author XiaoYan
*/
import { onMounted, onBeforeUnmount, ref } from "vue"
import * as echarts from "echarts"
import elementResizeDetectorMaker from "element-resize-detector"
import utils from "@/utils"
export default function useChart(refs, options) {
let chartInst
let chartRef = ref(null)
let erd = elementResizeDetectorMaker()
const handleResize = utils.debounce(() => {
chartInst.resize()
}, 100)
onMounted(() => {
if(refs.value) {
chartInst = echarts.init(refs.value)
chartInst.setOption(options)
chartRef.value = chartInst
}
// window.addEventListener('resize', handleResize)
erd.listenTo(refs.value, handleResize)
})
onBeforeUnmount(() => {
chartInst.dispose()
// window.removeEventListener('resize', handleResize)
erd.removeListener(refs.value, handleResize)
})
return chartRef
}
Okay,基于vite.js+vue3+electron开发管理后台就分享到这里。希望对小伙伴们有些帮助!
链接:https://juejin.cn/post/6963310387945013261/
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
uview组件from-item在小程序与h5里表现一不致(附解决方案)
在使用uview组件开发项目时,使用下面代码,碰到一个问题:
代码为:
<u-form class="from-submit" ref="uForm" label-width="160" :error-type="['toast', 'border-bottom']">
<u-form-item label="上课时间" prop="beginTime" class="u-flex" :required="true">
<view>xxx</view>
<text class="label-text">至</text>
<view>xxx</view>
</u-form-item>
</u-form>
大家看图:
可以发现,同一套代码,在两个平台,表现的却不是一致的。
同样是选择from-item,他们的显示区域却不尽相同。
虽然看起来样式差不多,但表现却不一致,通过调试,最终得到解决方案:
给from-item下面的view元素,添加 display:inline-flex 样式即可
最终代码(非优化代码,仅作示例):
<u-form class="from-submit" ref="uForm" label-width="160" :error-type="['toast', 'border-bottom']">
<u-form-item label="上课时间" prop="beginTime" class="u-flex" :required="true">
<view style="display: inline-flex;">xxx</view>
<text class="label-text">至</text>
<view style="display: inline-flex;">xxx</view>
</u-form-item>
</u-form>
最终效果,”鸡乎一样“ 了
在使用uview组件开发项目时,使用下面代码,碰到一个问题:
代码为:
<u-form class="from-submit" ref="uForm" label-width="160" :error-type="['toast', 'border-bottom']">
<u-form-item label="上课时间" prop="beginTime" class="u-flex" :required="true">
<view>xxx</view>
<text class="label-text">至</text>
<view>xxx</view>
</u-form-item>
</u-form>
大家看图:
可以发现,同一套代码,在两个平台,表现的却不是一致的。
同样是选择from-item,他们的显示区域却不尽相同。
虽然看起来样式差不多,但表现却不一致,通过调试,最终得到解决方案:
给from-item下面的view元素,添加 display:inline-flex 样式即可
最终代码(非优化代码,仅作示例):
<u-form class="from-submit" ref="uForm" label-width="160" :error-type="['toast', 'border-bottom']">
<u-form-item label="上课时间" prop="beginTime" class="u-flex" :required="true">
<view style="display: inline-flex;">xxx</view>
<text class="label-text">至</text>
<view style="display: inline-flex;">xxx</view>
</u-form-item>
</u-form>
最终效果,”鸡乎一样“ 了
收起阅读 »有丰富的uniapp开发经验,后端技术栈java,全栈工程师,接单
有丰富的uniapp开发经验,
后端技术栈java,
全栈工程师,
有充足的时间,
有需要的可以联系我
接单:微信小程序应用、uniapp开发、java开发、后台管理系统、APP、网站、vue开发。
联系方式Q.Q,V.X号:443409972
淘宝开发小店:https://item.taobao.com/item.htm?id=630595051308
有丰富的uniapp开发经验,
后端技术栈java,
全栈工程师,
有充足的时间,
有需要的可以联系我
接单:微信小程序应用、uniapp开发、java开发、后台管理系统、APP、网站、vue开发。
联系方式Q.Q,V.X号:443409972
淘宝开发小店:https://item.taobao.com/item.htm?id=630595051308
Android应用市场上架uni-app(5+App)应用合规指南,以及收到工信部或应用市场合规整改通知的解决办法
此文档将不再维护,请参考新文档:https://uniapp.dcloud.net.cn/tutorial/android-store
背景
为有效治理App强制授权、过度索权、超范围收集个人信息等现象,落实《网络安全法》《消费者权益保护法》的要求,保障个人信息安全,2019年1月,中央网信办、工信部、公安部、市场监管总局等四部委发布了《关于开展App违法违规收集使用个人信息专项治理的公告》,在全国范围组织开展App违法违规收集使用个人信息专项治理,并陆续出台完善了《App违法违规收集使用个人信息行为认定方法》、《GB/T 35273-2020 信息安全技术 个人信息安全规范》等标准规范。
根据以上规范要求,各大应用市场都加强应用的检测,要求应用必须符合相关政策,否则应用将有被通报或下架的风险。
APP因合规问题无法上架
请认真的阅读以下步骤来检测自己的APP!有效的解决上架问题
- APP不是由HbuilderX
3.6.1+云打包生产的请抓紧时间升级到HbuilderX3.6.1+版本。重新打包! - APP是离线打包请升级SDK到
3.6.1+版本重新编辑打包!下载地址 - 不要将自定义基座提交平台审核。调试模式下不会处理合规问题。需要注意!
- APP没有配置隐私与政策提示框。请认真阅读Android平台隐私与政策提示框配置方法配置你APP的隐私弹窗。
- 配置隐私弹窗时一定要配置使用
template模式。否则无法上架应用市场。应用内部自己实现的隐私弹窗也不行。一定要使用uni提供的隐私弹窗并使用template模式切记!//androidPrivacy.json { "version": "1", "prompt": "template", "title": "服务协议和隐私政策", "message": "..." } - 填写隐私协一定要结合实际使用的模块功能。填写相关隐私条款!不能含糊不清。模块收集了什么信息都要填写完整。否则影响上架!请参考当前文档中的
隐私政策注意事项 - 查看是否集成uni原生插件。有些权限或是违规获取可能是uni原生插件引发的。建议使用排除法删除插件重新打包检测
- 检查是否集成了fcm推送(包含unipush中的fcm)、google统计、google推送、google登录模块。由于这些模块都集成google的gms服务会提前获取android id导致无法在国内正常上架。打包时请在manifest.json配置中排除这些功能模块。
- APP都符合以上条件要求。上架依然失败!请向检测平台要求提供代码调用堆栈。请拿着堆栈信息去ASK论坛发帖说明问题并@管理人员反馈
<a id="zhuyishixiang">隐私政策注意事项</a>
- 必须确保应用存在《隐私政策》,在应用首次启动时弹出提示并取得用户同意。
- 一定要配置使用
template模式隐私与政策提示框 详情参考 - 必须在“隐私与政策”非常清楚、全面地说明(不要用可能收集、了解用户信息这种模糊不清晰的词语)收集用户个人信息的目的、方式和范围,用户个人信息包括但不限于mac地址、设备序列号、imei、imsi、软件安装列表、通讯录信息、短信信息等。
- 如果反馈说有违规获取敏感信息行为,请查看Android平台各功能模块隐私合规协议各功能模块隐私协议。如果你集成了相关模块就一定要写入到app的隐私协议中。
-
必须在《隐私政策》中必告知用户您的应用基于DCloud uni-app(5+ App/Wap2App)开发,添加如下协议:
我们的产品基于DCloud uni-app(5+ App/Wap2App)开发,应用运行期间需要收集您的设备唯一识别码(IMEI/android ID/DEVICE_ID/IDFA、SIM 卡 IMSI 信息、OAID)以提供统计分析服务,并通过应用启动数据及异常错误日志分析改进性能和用户体验,为用户提供更好的服务。
各大应用市场上架合规审查细节可能存在差异,如果开发者碰到相关问题请及时反馈,我们会及时汇总整理供大家参考
相关参考
- Android平台隐私与政策提示框配置方法:https://ask.dcloud.net.cn/article/36937
- Android平台应用启动时读写手机存储、访问设备信息(如IMEI)等权限策略及提示信息:https://ask.dcloud.net.cn/article/36549
- Android平台配置权限参考:https://ask.dcloud.net.cn/article/36982
此文档将不再维护,请参考新文档:https://uniapp.dcloud.net.cn/tutorial/android-store
背景
为有效治理App强制授权、过度索权、超范围收集个人信息等现象,落实《网络安全法》《消费者权益保护法》的要求,保障个人信息安全,2019年1月,中央网信办、工信部、公安部、市场监管总局等四部委发布了《关于开展App违法违规收集使用个人信息专项治理的公告》,在全国范围组织开展App违法违规收集使用个人信息专项治理,并陆续出台完善了《App违法违规收集使用个人信息行为认定方法》、《GB/T 35273-2020 信息安全技术 个人信息安全规范》等标准规范。
根据以上规范要求,各大应用市场都加强应用的检测,要求应用必须符合相关政策,否则应用将有被通报或下架的风险。
APP因合规问题无法上架
请认真的阅读以下步骤来检测自己的APP!有效的解决上架问题
- APP不是由HbuilderX
3.6.1+云打包生产的请抓紧时间升级到HbuilderX3.6.1+版本。重新打包! - APP是离线打包请升级SDK到
3.6.1+版本重新编辑打包!下载地址 - 不要将自定义基座提交平台审核。调试模式下不会处理合规问题。需要注意!
- APP没有配置隐私与政策提示框。请认真阅读Android平台隐私与政策提示框配置方法配置你APP的隐私弹窗。
- 配置隐私弹窗时一定要配置使用
template模式。否则无法上架应用市场。应用内部自己实现的隐私弹窗也不行。一定要使用uni提供的隐私弹窗并使用template模式切记!//androidPrivacy.json { "version": "1", "prompt": "template", "title": "服务协议和隐私政策", "message": "..." } - 填写隐私协一定要结合实际使用的模块功能。填写相关隐私条款!不能含糊不清。模块收集了什么信息都要填写完整。否则影响上架!请参考当前文档中的
隐私政策注意事项 - 查看是否集成uni原生插件。有些权限或是违规获取可能是uni原生插件引发的。建议使用排除法删除插件重新打包检测
- 检查是否集成了fcm推送(包含unipush中的fcm)、google统计、google推送、google登录模块。由于这些模块都集成google的gms服务会提前获取android id导致无法在国内正常上架。打包时请在manifest.json配置中排除这些功能模块。
- APP都符合以上条件要求。上架依然失败!请向检测平台要求提供代码调用堆栈。请拿着堆栈信息去ASK论坛发帖说明问题并@管理人员反馈
<a id="zhuyishixiang">隐私政策注意事项</a>
- 必须确保应用存在《隐私政策》,在应用首次启动时弹出提示并取得用户同意。
- 一定要配置使用
template模式隐私与政策提示框 详情参考 - 必须在“隐私与政策”非常清楚、全面地说明(不要用可能收集、了解用户信息这种模糊不清晰的词语)收集用户个人信息的目的、方式和范围,用户个人信息包括但不限于mac地址、设备序列号、imei、imsi、软件安装列表、通讯录信息、短信信息等。
- 如果反馈说有违规获取敏感信息行为,请查看Android平台各功能模块隐私合规协议各功能模块隐私协议。如果你集成了相关模块就一定要写入到app的隐私协议中。
-
必须在《隐私政策》中必告知用户您的应用基于DCloud uni-app(5+ App/Wap2App)开发,添加如下协议:
我们的产品基于DCloud uni-app(5+ App/Wap2App)开发,应用运行期间需要收集您的设备唯一识别码(IMEI/android ID/DEVICE_ID/IDFA、SIM 卡 IMSI 信息、OAID)以提供统计分析服务,并通过应用启动数据及异常错误日志分析改进性能和用户体验,为用户提供更好的服务。
各大应用市场上架合规审查细节可能存在差异,如果开发者碰到相关问题请及时反馈,我们会及时汇总整理供大家参考
相关参考
- Android平台隐私与政策提示框配置方法:https://ask.dcloud.net.cn/article/36937
- Android平台应用启动时读写手机存储、访问设备信息(如IMEI)等权限策略及提示信息:https://ask.dcloud.net.cn/article/36549
- Android平台配置权限参考:https://ask.dcloud.net.cn/article/36982
提示appkey未配置,请检查build.gradle
配置signingConfigs节点下的证书,
buildTypes节点下minifyEnabled改为true,官方给的demo这里是false,严重怀疑官方故意误导!
signingConfigs {
config {
keyAlias ''
keyPassword ''
storeFile file('.jks')
storePassword ''
v1SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
debug {
signingConfig signingConfigs.config
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
signingConfig signingConfigs.config
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
} 配置signingConfigs节点下的证书,
buildTypes节点下minifyEnabled改为true,官方给的demo这里是false,严重怀疑官方故意误导!
signingConfigs {
config {
keyAlias ''
keyPassword ''
storeFile file('.jks')
storePassword ''
v1SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
debug {
signingConfig signingConfigs.config
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
signingConfig signingConfigs.config
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
} 收起阅读 »
95 后大学生利用漏洞免费吃肯德基,获刑2年半!
日前,在校大学生徐某利用肯德基App客户端和微信客户端之间数据不同步的漏洞,骗取兑换券或取餐码,售与他人牟利,并将诈骗方法传授给同学,造成肯德基品牌所有者百胜公司损失20余万元。
近日,上海市徐汇区人民法院开庭审理此案。徐某等五人因犯诈骗罪、传授犯罪方法罪被判有期徒刑,并处罚金。
大学生钻肯德基系统漏洞,生出意外“副业”获利
徐某是江苏某大学的一名在校生。2018年4月,在用肯德基客户端点餐时,徐某无意发现两个“生财小门道”。
-
一是在App客户端用套餐兑换券下单,进入待支付状态后暂不支付,之后在微信客户端对兑换券进行退款操作,然后再将之前客户端的订单取消,此时竟可以重新获取兑换券,这种方式等于分文未付骗取一份兑换券。
-
二是先在App客户端用套餐兑换券下单待支付,在微信客户端退掉兑换券,再在App客户端支付,此时便可以支付成功并获得取餐码,这种方式等于分文未付骗取一份套餐。
发现这个漏洞后,徐某“喜出望外”。从当年4月起,除了自己这样点餐操作外,徐某还做起了“副业”:将诈骗得来的套餐产品通过线上交易软件低价出售给他人,从中非法获利。
同时,他还将犯罪方法当面或通过网络传授给丁某等四名同学。截至同年10月案发,徐某的行为造成百胜公司损失5.8万余元,丁某等四人造成百胜公司损失0.89万元至4.7万元不等。
法院:符合诈骗罪构成要件,5名大学生悉数获刑
上海市徐汇区人民法院审理查明,各被告人利用系统的数据不同步来实施犯罪,并非系统本身发生的机械故障或者缺陷,其行为存在欺骗性。
法院认定,各被告人明知百胜公司旗下品牌肯德基App客户端和微信客户端自助点餐系统存在数据不同步的漏洞,仍以非法占有为目的,进行虚假交易,进而非法获取财物的行为认定为诈骗罪。
法院审理后认为,被告人徐某以非法占有为目的,诈骗单位财物,数额巨大,并传授他人犯罪方法,其行为分别构成诈骗罪、传授犯罪方法罪。
徐某自动投案,如实供述诈骗和传授犯罪方法罪行,均系自首,依法分别予以减轻、从轻处罚。同时,徐某积极赔偿被害单位损失并获谅解,酌情予以从轻处罚。
最终,徐某因犯诈骗罪,被判处有期徒刑两年,并处罚金人民币六千元;犯传授犯罪方法罪,判处有期徒刑十个月,决定执行有期徒刑两年六个月,并处罚金人民币六千元。
丁某等四人皆因相同案由被分别认定为诈骗罪或诈骗罪、传授犯罪方法罪,分别被判处有期徒刑两年至一年三个月,并处罚金人民币四千元至一千元不等的刑罚。
网友:聪明脑袋算了笔糊涂账
对此,网友纷纷表示,“聪明用错了地方”“做任何事不能违背法律”。
【来源:光明日报】,声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。 邮箱地址:pufa@dcloud.io 。
日前,在校大学生徐某利用肯德基App客户端和微信客户端之间数据不同步的漏洞,骗取兑换券或取餐码,售与他人牟利,并将诈骗方法传授给同学,造成肯德基品牌所有者百胜公司损失20余万元。
近日,上海市徐汇区人民法院开庭审理此案。徐某等五人因犯诈骗罪、传授犯罪方法罪被判有期徒刑,并处罚金。
大学生钻肯德基系统漏洞,生出意外“副业”获利
徐某是江苏某大学的一名在校生。2018年4月,在用肯德基客户端点餐时,徐某无意发现两个“生财小门道”。
-
一是在App客户端用套餐兑换券下单,进入待支付状态后暂不支付,之后在微信客户端对兑换券进行退款操作,然后再将之前客户端的订单取消,此时竟可以重新获取兑换券,这种方式等于分文未付骗取一份兑换券。
-
二是先在App客户端用套餐兑换券下单待支付,在微信客户端退掉兑换券,再在App客户端支付,此时便可以支付成功并获得取餐码,这种方式等于分文未付骗取一份套餐。
发现这个漏洞后,徐某“喜出望外”。从当年4月起,除了自己这样点餐操作外,徐某还做起了“副业”:将诈骗得来的套餐产品通过线上交易软件低价出售给他人,从中非法获利。
同时,他还将犯罪方法当面或通过网络传授给丁某等四名同学。截至同年10月案发,徐某的行为造成百胜公司损失5.8万余元,丁某等四人造成百胜公司损失0.89万元至4.7万元不等。
法院:符合诈骗罪构成要件,5名大学生悉数获刑
上海市徐汇区人民法院审理查明,各被告人利用系统的数据不同步来实施犯罪,并非系统本身发生的机械故障或者缺陷,其行为存在欺骗性。
法院认定,各被告人明知百胜公司旗下品牌肯德基App客户端和微信客户端自助点餐系统存在数据不同步的漏洞,仍以非法占有为目的,进行虚假交易,进而非法获取财物的行为认定为诈骗罪。
法院审理后认为,被告人徐某以非法占有为目的,诈骗单位财物,数额巨大,并传授他人犯罪方法,其行为分别构成诈骗罪、传授犯罪方法罪。
徐某自动投案,如实供述诈骗和传授犯罪方法罪行,均系自首,依法分别予以减轻、从轻处罚。同时,徐某积极赔偿被害单位损失并获谅解,酌情予以从轻处罚。
最终,徐某因犯诈骗罪,被判处有期徒刑两年,并处罚金人民币六千元;犯传授犯罪方法罪,判处有期徒刑十个月,决定执行有期徒刑两年六个月,并处罚金人民币六千元。
丁某等四人皆因相同案由被分别认定为诈骗罪或诈骗罪、传授犯罪方法罪,分别被判处有期徒刑两年至一年三个月,并处罚金人民币四千元至一千元不等的刑罚。
网友:聪明脑袋算了笔糊涂账
对此,网友纷纷表示,“聪明用错了地方”“做任何事不能违背法律”。
【来源:光明日报】,声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。 邮箱地址:pufa@dcloud.io 。
收起阅读 »uni-rate 评分 点击评分失效问题解决
-
定位到 _getRateCount(获取星星个数) 方法,进行替换,替换代码如下。
/** * 获取星星个数 */ _getRateCount(clientX) { this._getSize() const size = Number(this.size) if(size === NaN){ return new Error('size 属性只能设置为数字') } const rateMoveRange = clientX - this._rateBoxLeft let index = parseInt(rateMoveRange / (size/2 + this.marginNumber)) index = index < 0 ? 0 : index; index = index > this.max ? this.max : index; const range = parseInt(rateMoveRange - (size/2 + this.marginNumber) * index); let value = 0; if (this._oldValue === index && !this.PC) return; this._oldValue = index; if (this.allowHalf) { if (range > (size / 2)) { value = index + 1 } else { value = index + 0.5 } } else { value = index + 1 } value = Math.max(0.5, Math.min(value, this.max)) this.valueSync = value this._onChange() },
原因
rpx和px问题
let index = parseInt(rateMoveRange / (size + this.marginNumber)) -> let index = parseInt(rateMoveRange / (size/2 + this.marginNumber))
const range = parseInt(rateMoveRange - (size + this.marginNumber) index); -> const range = parseInt(rateMoveRange - (size/2 + this.marginNumber) index
-
定位到 _getRateCount(获取星星个数) 方法,进行替换,替换代码如下。
/** * 获取星星个数 */ _getRateCount(clientX) { this._getSize() const size = Number(this.size) if(size === NaN){ return new Error('size 属性只能设置为数字') } const rateMoveRange = clientX - this._rateBoxLeft let index = parseInt(rateMoveRange / (size/2 + this.marginNumber)) index = index < 0 ? 0 : index; index = index > this.max ? this.max : index; const range = parseInt(rateMoveRange - (size/2 + this.marginNumber) * index); let value = 0; if (this._oldValue === index && !this.PC) return; this._oldValue = index; if (this.allowHalf) { if (range > (size / 2)) { value = index + 1 } else { value = index + 0.5 } } else { value = index + 1 } value = Math.max(0.5, Math.min(value, this.max)) this.valueSync = value this._onChange() },
原因
rpx和px问题
let index = parseInt(rateMoveRange / (size + this.marginNumber)) -> let index = parseInt(rateMoveRange / (size/2 + this.marginNumber))
const range = parseInt(rateMoveRange - (size + this.marginNumber) index); -> const range = parseInt(rateMoveRange - (size/2 + this.marginNumber) index
Vue3简单整合uView@1.8.4解决方案
仅仅可以跑DEMO,嘿嘿嘿
问题描述
问题分析
官方文档
解决方案
切换到下载安装方式
https://www.uviewui.com/components/install.html#下载安装
修改源代码
index.js
Vue3 filter也没了,几个时间函数不重要吧?
![]()

const install = Vue => {
Vue.mixin(mixin)
if (Vue.config.globalProperties.openShare) {
Vue.mixin(mpShare);
}
// Vue.mixin(vuexStore);
// 时间格式化,同时两个名称,date和timeFormat
Vue.config.globalProperties.$filter = {
timeFormat(timestamp, format) {
return timeFormat(timestamp, format)
},
date(timestamp, format) {
return timeFormat(timestamp, format)
},
// 将多久以前的方法,注入到全局过滤器
timeFrom(timestamp, format) {
return timeFrom(timestamp, format)
}
}
Vue.config.globalProperties.$u = $u
}
参考文章
仅仅可以跑DEMO,嘿嘿嘿
问题描述
问题分析
官方文档
解决方案
切换到下载安装方式
https://www.uviewui.com/components/install.html#下载安装
修改源代码
index.js
Vue3 filter也没了,几个时间函数不重要吧?
![]()

const install = Vue => {
Vue.mixin(mixin)
if (Vue.config.globalProperties.openShare) {
Vue.mixin(mpShare);
}
// Vue.mixin(vuexStore);
// 时间格式化,同时两个名称,date和timeFormat
Vue.config.globalProperties.$filter = {
timeFormat(timestamp, format) {
return timeFormat(timestamp, format)
},
date(timestamp, format) {
return timeFormat(timestamp, format)
},
// 将多久以前的方法,注入到全局过滤器
timeFrom(timestamp, format) {
return timeFrom(timestamp, format)
}
}
Vue.config.globalProperties.$u = $u
}
参考文章
收起阅读 »不能获取到别人帮我买的付费插件
别人帮我购买了一个付费插件, appid和package name 都填写正确。 却在HbuilderX中获取不到这个插件
别人帮我购买了一个付费插件, appid和package name 都填写正确。 却在HbuilderX中获取不到这个插件
nvue waterfall原生组件返回顶部
在解决这个问题之前,可是浪费了我好久的时间
也有其他人在发布了问题,但是没有人回答
在详细查阅文档后,还是找到了答案
确实还是对文档的不够熟悉
在此记录下,也给后面的小白找好捷径,代码已精简
<template>
<waterfall column-count="2" column-width="auto" :show-scrollbar="false" :column-gap="5" :left-gap="5"
:right-gap="5" :bounce="false" :loadmoreoffset="500" @loadmore="loadmore" alwaysScrollableVertical="true"
:style="{height: contentHeight + 'px'}">
<header>
<view ref="topRef" style="height: 0;">顶部标志</view>
</header>
<!-- 注意事项: 不能使用 index 作为 key 的唯一标识 -->
<cell v-for="(item, index) in dataList" :key="'list_'+index">
</cell>
</waterfall>
<cover-view style="position: fixed;right:10rpx;bottom:20rpx;background-color: #ffe563;" @click="goTop()">
<text>返回顶部</text>
</cover-view>
<template>
<script>
const dom = uni.requireNativePlugin('dom')
export default {
props: {
contentHeight: {
type: Number,
default: 800
}
},
data() {
return {
dataList: []
}
},
methods: {
goTop() {
dom.scrollToElement(this.$refs.topRef, {
offset: 0
})
}
}
}
</script> 在解决这个问题之前,可是浪费了我好久的时间
也有其他人在发布了问题,但是没有人回答
在详细查阅文档后,还是找到了答案
确实还是对文档的不够熟悉
在此记录下,也给后面的小白找好捷径,代码已精简
<template>
<waterfall column-count="2" column-width="auto" :show-scrollbar="false" :column-gap="5" :left-gap="5"
:right-gap="5" :bounce="false" :loadmoreoffset="500" @loadmore="loadmore" alwaysScrollableVertical="true"
:style="{height: contentHeight + 'px'}">
<header>
<view ref="topRef" style="height: 0;">顶部标志</view>
</header>
<!-- 注意事项: 不能使用 index 作为 key 的唯一标识 -->
<cell v-for="(item, index) in dataList" :key="'list_'+index">
</cell>
</waterfall>
<cover-view style="position: fixed;right:10rpx;bottom:20rpx;background-color: #ffe563;" @click="goTop()">
<text>返回顶部</text>
</cover-view>
<template>
<script>
const dom = uni.requireNativePlugin('dom')
export default {
props: {
contentHeight: {
type: Number,
default: 800
}
},
data() {
return {
dataList: []
}
},
methods: {
goTop() {
dom.scrollToElement(this.$refs.topRef, {
offset: 0
})
}
}
}
</script> 收起阅读 »

















