
关于使用条件编译时遇到的问题和一些想法
目前的条件编译是使用注释和目录区分的方式实现,但是在实际开发中会遇到几个问题。
1. pages.json中的注释会破坏JSON结构
在pages.json中使用注释的方式实现条件编译,会破坏JSON结构,会导致部分IDE报错,虽然不影响最终使用,但是在开发时还是会影响体验。
建议可以pages.json中,在保持JSON结构不变的情况下,支持对不同终端的配置。例:
{
"pages": [
{
"path": "pages/index/index"
}
],
"globalStyle": {
"enablePullDownRefresh": false
},
"platforms": {
"mp-weixin": {
"pages": [
{
"path": "pages/login/index"
}
],
"globalStyle": {
"enablePullDownRefresh": true
}
}
}
}
在编译微信小程序时,会把"pages/login/index"页面也编译进去,另外覆盖合并其他配置到默认配置上。
2. 在JS脚本中条件注释可能会导致IDE报错和代码质量检测失败。
比如以下代码:
function login(payload) {
// #ifdef H5
return redirectTo({
url: "/pages/login/index",
payload
});
// #endif
// #ifdef MP
return uni.login(payload);
// #endif
}
对于代码检查工具来说,return之后紧接着又是一个return,本身就是一段“有问题”的代码。而且如果逻辑复杂,会影响代码阅读。
对于此问题,我有2点建议:
1是支持使用环境变量做条件编译:比如:
function login(payload) {
if (process.env.UNI_PLATFORM === "h5") {
return redirectTo({
url: "/pages/login/index",
payload
});
}
if (process.env.UNI_PLATFORM === "mp-weixin") {
return uni.login(payload);
}
}
2是支持按平台区分文件。比如login.h5.js,login.mp-weixin.js。import 文件时,只需要import login即可,编译器自动优先编译对应的文件。在开发时,只要保持多端文件export一致即可。
login.js(没有对应平台文件时,才编译此文件)
login.h5.js
login.mp-weixin.js
3. 使用整体目录条件编译,会导致路由不一致。
如果要实现同样的路由,不同平台编译时编译不同的问题,就需要破坏路由,比如:
// pages.json
{
"pages": [
// #ifdef h5
{
"path": "pages/login/index"
},
// #endif
// #ifdef mp-weixin
{
"path": "platform/mp-weixin/login/index"
}
// #endif
]
}
本来都是登录页,需要保持路由的一致,但是如果按平台区分文件,那么就必须要拆成两个路由。
对此,我建议可以支持按文件后缀来区分平台:
比如在编译微信小程序时,优先编译/pages/login/index.mp-weixin.vue,如果文件不存在,才编译/pages/login/index.vue。这样既能保证路由一致,又可以通过区分文件实现条件编译。
以上是本人在开发中遇到的实际问题和产生的一些想法,如有不完善的地方还请大家指教。
目前的条件编译是使用注释和目录区分的方式实现,但是在实际开发中会遇到几个问题。
1. pages.json中的注释会破坏JSON结构
在pages.json中使用注释的方式实现条件编译,会破坏JSON结构,会导致部分IDE报错,虽然不影响最终使用,但是在开发时还是会影响体验。
建议可以pages.json中,在保持JSON结构不变的情况下,支持对不同终端的配置。例:
{
"pages": [
{
"path": "pages/index/index"
}
],
"globalStyle": {
"enablePullDownRefresh": false
},
"platforms": {
"mp-weixin": {
"pages": [
{
"path": "pages/login/index"
}
],
"globalStyle": {
"enablePullDownRefresh": true
}
}
}
}
在编译微信小程序时,会把"pages/login/index"页面也编译进去,另外覆盖合并其他配置到默认配置上。
2. 在JS脚本中条件注释可能会导致IDE报错和代码质量检测失败。
比如以下代码:
function login(payload) {
// #ifdef H5
return redirectTo({
url: "/pages/login/index",
payload
});
// #endif
// #ifdef MP
return uni.login(payload);
// #endif
}
对于代码检查工具来说,return之后紧接着又是一个return,本身就是一段“有问题”的代码。而且如果逻辑复杂,会影响代码阅读。
对于此问题,我有2点建议:
1是支持使用环境变量做条件编译:比如:
function login(payload) {
if (process.env.UNI_PLATFORM === "h5") {
return redirectTo({
url: "/pages/login/index",
payload
});
}
if (process.env.UNI_PLATFORM === "mp-weixin") {
return uni.login(payload);
}
}
2是支持按平台区分文件。比如login.h5.js,login.mp-weixin.js。import 文件时,只需要import login即可,编译器自动优先编译对应的文件。在开发时,只要保持多端文件export一致即可。
login.js(没有对应平台文件时,才编译此文件)
login.h5.js
login.mp-weixin.js
3. 使用整体目录条件编译,会导致路由不一致。
如果要实现同样的路由,不同平台编译时编译不同的问题,就需要破坏路由,比如:
// pages.json
{
"pages": [
// #ifdef h5
{
"path": "pages/login/index"
},
// #endif
// #ifdef mp-weixin
{
"path": "platform/mp-weixin/login/index"
}
// #endif
]
}
本来都是登录页,需要保持路由的一致,但是如果按平台区分文件,那么就必须要拆成两个路由。
对此,我建议可以支持按文件后缀来区分平台:
比如在编译微信小程序时,优先编译/pages/login/index.mp-weixin.vue,如果文件不存在,才编译/pages/login/index.vue。这样既能保证路由一致,又可以通过区分文件实现条件编译。
以上是本人在开发中遇到的实际问题和产生的一些想法,如有不完善的地方还请大家指教。
收起阅读 »
uni-app input高度无法&&失效调整
发现设置字体后能影响高度:
//自定义样式
.numInput{
min-height: 15upx !important;
height: 15upx !important;
padding: 0 !important;
margin: 0 !important;
font-size: 15upx;
}
发现设置字体后能影响高度:
//自定义样式
.numInput{
min-height: 15upx !important;
height: 15upx !important;
padding: 0 !important;
margin: 0 !important;
font-size: 15upx;
}

莹石云(EZVIZ) 实时视频预览、录像回放、语音对讲
莹石云(EZVIZ) 实时视频预览、录像回放、语音对讲插件地址:https://ext.dcloud.net.cn/plugin?id=2454
莹石云(EZVIZ) 实时视频预览、录像回放、语音对讲插件地址:https://ext.dcloud.net.cn/plugin?id=2454

强烈建议 d-cloud 布局手机系统 国产手机系统靠你们啦
强烈建议 d-cloud 布局手机系统,在目前的时代背景下,国产手机系统有百年不遇的时机啊
众所周知 手机系统并不是很难的东西
难的是手机系统的生态
安卓之所以强大 是因为有几千万的APP
国内 目前 alibaba tencent 都有研发手机系统的能力 但是他们不敢做的原因 是怕m国制裁
搞手机系统必须要大涨旗鼓的搞 如果一旦搞出点成绩 m国一定会制裁
所以 alibaba tencent 都不敢搞
小米 OPPO 等 手机厂商中 小米应该也是有研发能力的 可能有储备手机系统 但是不敢发布 也是怕制裁 怕不给芯片
小米有自己的miui 其实就用个安卓的内核 小米如果发布手机系统 安卓肯定不让小米用了
那小米就会很尴尬 新系统没有生态 用户不买账 安卓又不能用了
华为虽然被迫发布了手机系统 但是依然没有生态
而 D-CLOUD 就不一样了
你有开发者资源 你搞手机系统 只需要uniApp 顺带多编译个端就行了
适应目前的手机架构
作为第三方ROM 适配一些机型刷入 形成生态后 就和手机厂商合作
国产手机厂商肯定会支持的呀
强烈建议 d-cloud 布局手机系统,在目前的时代背景下,国产手机系统有百年不遇的时机啊
众所周知 手机系统并不是很难的东西
难的是手机系统的生态
安卓之所以强大 是因为有几千万的APP
国内 目前 alibaba tencent 都有研发手机系统的能力 但是他们不敢做的原因 是怕m国制裁
搞手机系统必须要大涨旗鼓的搞 如果一旦搞出点成绩 m国一定会制裁
所以 alibaba tencent 都不敢搞
小米 OPPO 等 手机厂商中 小米应该也是有研发能力的 可能有储备手机系统 但是不敢发布 也是怕制裁 怕不给芯片
小米有自己的miui 其实就用个安卓的内核 小米如果发布手机系统 安卓肯定不让小米用了
那小米就会很尴尬 新系统没有生态 用户不买账 安卓又不能用了
华为虽然被迫发布了手机系统 但是依然没有生态
而 D-CLOUD 就不一样了
你有开发者资源 你搞手机系统 只需要uniApp 顺带多编译个端就行了
适应目前的手机架构
作为第三方ROM 适配一些机型刷入 形成生态后 就和手机厂商合作
国产手机厂商肯定会支持的呀

小程序debug技巧,让调试更加方便
小程序debug更加方便
众所周知,小程序的调试工具是不支持vue devtool 的,我们有的时候想要调试一个响应式变量都需要通过事件或者把vm引用到全局变量上
这样做有些繁琐,所以经过我长时间的摸索总结出以下的方案用于微信小程序的调试
- 我们使用vue devtool 的时候如果选择了一个组件默认的情况下会把当前实例的引用添加到全局上面,默认的名称为
$vm
+数字 - 本着这种目的我写了一个vue全局混入来吧页面级别的组件添加到全局上
- 我还编写了一个可以通过组件名称搜索的全局函数
searchComponentByName
暴露在全局上面方便查找组件 - vue和vuex事件控制台输出
// debugMiddleware.js
const exportFn = process.env.NODE_ENV === 'development' ? function(Vue) {
if (process.env.NODE_ENV === 'development') {
// 挂载对象,如果parent对象存在就使用parent(window),不然就是用 Object
const mountObj = typeof parent === 'object' ? parent : Object
// 广度优先遍历搜索组件
// eslint-disable-next-line no-inner-declarations
function searchComponentByName(root, keyword) {
// 第一个参数不是对象,那么就是直接通过根元素进行搜索
if (typeof root !== 'object') {
keyword = root
root = mountObj.$vmRoot
}
// keyword 支持字符串或者正则表达式
if (typeof keyword === 'string') {
keyword = keyword.toUpperCase()
}
if (!root || !root.$children || root.$children.length === 0) {
return null
}
const stack = [root]
let current
// eslint-disable-next-line no-cond-assign
while (current = stack.shift()) {
if (current.$options && current.$options.name && current.$options.name.toUpperCase().match(keyword)) {
return current
}
if (current.$children && current.$children.length !== 0) {
stack.push(...current.$children)
}
}
}
// 在全局暴露一个通过组件名称搜索的函数
mountObj.searchComponentByName = searchComponentByName
// // 函数劫持,劫持 uni.$emit 用于控制台打印
const oldUniEmit = uni.$emit
// uni.$emit 依赖于vue事件流,uni.$emit属于全局事件
let isEmitGlobal = false
uni.$emit = function(eventName, param) {
isEmitGlobal = true
return oldUniEmit.apply(uni, arguments)
}
const oldVueEmmit = Vue.prototype.$emit
Vue.prototype.$emit = function(event, args) {
console.info(`%c ${isEmitGlobal ? 'global' : 'Vue'}.$emit `, `background-color: #41b883;color: #fff`, `${event}`, args, this)
isEmitGlobal = false
return oldVueEmmit.apply(this, arguments)
}
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
this.$options.store.subscribe((mutation, state) => {
console.info(`%c Vux.mutation `, `background-color: #41b883;color: #fff`, `${mutation.type}`, mutation.payload)
})
this.$options.store.subscribeAction((action, state) => {
console.info(`%c Vuex.action `, `background-color: #41b883;color: #fff`, `${action.type}`, action.payload)
})
}
},
created() {
if (process.env.NODE_ENV === 'development') {
// 如果当前组件类型是页面就把this挂载
if (this.mpType === 'page') {
mountObj.__count = mountObj.__count ? mountObj.__count++ : 1
const count = mountObj.__count
mountObj['$vm' + count] = this
// 把root挂载到全局
mountObj.$vmRoot = this.$root
}
}
},
beforeDestroy() {
if (process.env.NODE_ENV === 'development') {
if (this.mpType === 'page') {
if (mountObj.__count) {
mountObj.__count--
}
}
}
}
})
}
} : null
export default exportFn
// main.js
// 如果测试环境就给所有组件添加debugMiddleware
if (process.env.NODE_ENV === 'development') {
Vue.use(debugMiddleware)
}
这样我们就可以在小程序控制台通过 $vm1 获取到当前页面的引用
小程序debug更加方便
众所周知,小程序的调试工具是不支持vue devtool 的,我们有的时候想要调试一个响应式变量都需要通过事件或者把vm引用到全局变量上
这样做有些繁琐,所以经过我长时间的摸索总结出以下的方案用于微信小程序的调试
- 我们使用vue devtool 的时候如果选择了一个组件默认的情况下会把当前实例的引用添加到全局上面,默认的名称为
$vm
+数字 - 本着这种目的我写了一个vue全局混入来吧页面级别的组件添加到全局上
- 我还编写了一个可以通过组件名称搜索的全局函数
searchComponentByName
暴露在全局上面方便查找组件 - vue和vuex事件控制台输出
// debugMiddleware.js
const exportFn = process.env.NODE_ENV === 'development' ? function(Vue) {
if (process.env.NODE_ENV === 'development') {
// 挂载对象,如果parent对象存在就使用parent(window),不然就是用 Object
const mountObj = typeof parent === 'object' ? parent : Object
// 广度优先遍历搜索组件
// eslint-disable-next-line no-inner-declarations
function searchComponentByName(root, keyword) {
// 第一个参数不是对象,那么就是直接通过根元素进行搜索
if (typeof root !== 'object') {
keyword = root
root = mountObj.$vmRoot
}
// keyword 支持字符串或者正则表达式
if (typeof keyword === 'string') {
keyword = keyword.toUpperCase()
}
if (!root || !root.$children || root.$children.length === 0) {
return null
}
const stack = [root]
let current
// eslint-disable-next-line no-cond-assign
while (current = stack.shift()) {
if (current.$options && current.$options.name && current.$options.name.toUpperCase().match(keyword)) {
return current
}
if (current.$children && current.$children.length !== 0) {
stack.push(...current.$children)
}
}
}
// 在全局暴露一个通过组件名称搜索的函数
mountObj.searchComponentByName = searchComponentByName
// // 函数劫持,劫持 uni.$emit 用于控制台打印
const oldUniEmit = uni.$emit
// uni.$emit 依赖于vue事件流,uni.$emit属于全局事件
let isEmitGlobal = false
uni.$emit = function(eventName, param) {
isEmitGlobal = true
return oldUniEmit.apply(uni, arguments)
}
const oldVueEmmit = Vue.prototype.$emit
Vue.prototype.$emit = function(event, args) {
console.info(`%c ${isEmitGlobal ? 'global' : 'Vue'}.$emit `, `background-color: #41b883;color: #fff`, `${event}`, args, this)
isEmitGlobal = false
return oldVueEmmit.apply(this, arguments)
}
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
this.$options.store.subscribe((mutation, state) => {
console.info(`%c Vux.mutation `, `background-color: #41b883;color: #fff`, `${mutation.type}`, mutation.payload)
})
this.$options.store.subscribeAction((action, state) => {
console.info(`%c Vuex.action `, `background-color: #41b883;color: #fff`, `${action.type}`, action.payload)
})
}
},
created() {
if (process.env.NODE_ENV === 'development') {
// 如果当前组件类型是页面就把this挂载
if (this.mpType === 'page') {
mountObj.__count = mountObj.__count ? mountObj.__count++ : 1
const count = mountObj.__count
mountObj['$vm' + count] = this
// 把root挂载到全局
mountObj.$vmRoot = this.$root
}
}
},
beforeDestroy() {
if (process.env.NODE_ENV === 'development') {
if (this.mpType === 'page') {
if (mountObj.__count) {
mountObj.__count--
}
}
}
}
})
}
} : null
export default exportFn
// main.js
// 如果测试环境就给所有组件添加debugMiddleware
if (process.env.NODE_ENV === 'development') {
Vue.use(debugMiddleware)
}
这样我们就可以在小程序控制台通过 $vm1 获取到当前页面的引用
收起阅读 »
关于scroll-view 实现区域滚动 及scroll-top不生效的问题
简书地址-----------------------------简书地址------------------------
分享这个主要是遇到两个坑
1.上下滚动因为高度的问题,scrollView没有填满所剩下的空间,没有实现区域滚动
-
scroll-top 不生效的问题 ,比如想滚动到底部
在用这个标签之前,很多地方需要阅读官方文档比如这句话 :用竖向滚动时,需要给 <scroll-view> 一个固定高度,通过 css 设置 height。
我的第二个问题就是因为没有设置高度导致 scroll-top不生效,但是设置高度百分之百又满足不了区域滚动,设置百分之分有时还会错位
好了不比比,直接上代码,建议全部复制过去<template> <view class="content flex-column"> <view class="top-view flex-center" @tap="clickEvnet(0)"> 点击我实现滚动到顶部 </view> <view class="scroll-view flex-1"> <scroll-view :scroll-y="true" :scroll-top="scrollTop" :style="{'height':scrollViewH}" scroll-with-animation="true"> <block v-for="(item,index) in list" :key="index"> <view class="item-view"> {{item}} </view> </block> </scroll-view> </view> <view class="bottom-view flex-center" @tap="clickEvnet(1)"> 点击我实现滚动到底部 </view> </view> </template>
<script> export default { data() { return { scrollViewH: "", scrollTop: 0, list: [] } }, onLoad(options) { let that = this; for (var i = 0; i < 100; i++) { that.list.push("滚动列表内容" + i) } }, mounted() { let that = this; const query = uni.createSelectorQuery().in(this); query.select('.scroll-view').boundingClientRect(); query.exec(res => { const scrollViewH = res[0].height; console.log("scrollViewH==" + scrollViewH) that.scrollViewH = scrollViewH + "px" }); }, methods: { clickEvnet(type) { let that = this; that.goToBottom(type == 0 ? 0 : 99999) }, // 容器滚动到底部 goToBottom(scrollTop) { let that = this that.scrollTop = scrollTop + Math.random() * 10 }, } } </script>
<style> .content { height: 100%; } .flex-column { display: flex; flex-direction: column; } .flex-center{ align-items:center; justify-content:center; } .flex-1 { flex: 1; } .scroll-view { background-color: red; overflow: hidden; } .top-view, .bottom-view { background-color: #0081FF; height: 50px; color: #fff; font-size: 18px; } .item-view { color: #333333; padding: 10px; border-bottom: 1px solid #888888; } </style>
简书地址-----------------------------简书地址------------------------
分享这个主要是遇到两个坑
1.上下滚动因为高度的问题,scrollView没有填满所剩下的空间,没有实现区域滚动
-
scroll-top 不生效的问题 ,比如想滚动到底部
在用这个标签之前,很多地方需要阅读官方文档比如这句话 :用竖向滚动时,需要给 <scroll-view> 一个固定高度,通过 css 设置 height。
我的第二个问题就是因为没有设置高度导致 scroll-top不生效,但是设置高度百分之百又满足不了区域滚动,设置百分之分有时还会错位
好了不比比,直接上代码,建议全部复制过去<template> <view class="content flex-column"> <view class="top-view flex-center" @tap="clickEvnet(0)"> 点击我实现滚动到顶部 </view> <view class="scroll-view flex-1"> <scroll-view :scroll-y="true" :scroll-top="scrollTop" :style="{'height':scrollViewH}" scroll-with-animation="true"> <block v-for="(item,index) in list" :key="index"> <view class="item-view"> {{item}} </view> </block> </scroll-view> </view> <view class="bottom-view flex-center" @tap="clickEvnet(1)"> 点击我实现滚动到底部 </view> </view> </template>
<script> export default { data() { return { scrollViewH: "", scrollTop: 0, list: [] } }, onLoad(options) { let that = this; for (var i = 0; i < 100; i++) { that.list.push("滚动列表内容" + i) } }, mounted() { let that = this; const query = uni.createSelectorQuery().in(this); query.select('.scroll-view').boundingClientRect(); query.exec(res => { const scrollViewH = res[0].height; console.log("scrollViewH==" + scrollViewH) that.scrollViewH = scrollViewH + "px" }); }, methods: { clickEvnet(type) { let that = this; that.goToBottom(type == 0 ? 0 : 99999) }, // 容器滚动到底部 goToBottom(scrollTop) { let that = this that.scrollTop = scrollTop + Math.random() * 10 }, } } </script>
<style> .content { height: 100%; } .flex-column { display: flex; flex-direction: column; } .flex-center{ align-items:center; justify-content:center; } .flex-1 { flex: 1; } .scroll-view { background-color: red; overflow: hidden; } .top-view, .bottom-view { background-color: #0081FF; height: 50px; color: #fff; font-size: 18px; } .item-view { color: #333333; padding: 10px; border-bottom: 1px solid #888888; } </style>

苹果审核问题 怎么设置只用于iphone 而不是ipad
Guideline 2.1 - Performance - App Completeness
We continue to discover one or more bugs in your app when reviewed on iPad running iOS 13.6 on Wi-Fi.
Specifically, your app did not load content properly when we tapped the buttons in the marked area in attached screenshot; no content was shown after we tapped the buttons in 更多分类
Next Steps
To resolve this issue, please run your app on a device to identify any issues, then revise and resubmit your app for review.
If we misunderstood the intended behavior of your app, please reply to this message in Resolution Center to provide information on how these features were intended to work.
For new apps, uninstall all previous versions of your app from a device, then install and follow the steps to reproduce the issue. For updates, install the new version as an update to the previous version, then follow the steps to reproduce the issue.
Guideline 2.1 - Performance - App Completeness
We continue to discover one or more bugs in your app when reviewed on iPad running iOS 13.6 on Wi-Fi.
Specifically, your app did not load content properly when we tapped the buttons in the marked area in attached screenshot; no content was shown after we tapped the buttons in 更多分类
Next Steps
To resolve this issue, please run your app on a device to identify any issues, then revise and resubmit your app for review.
If we misunderstood the intended behavior of your app, please reply to this message in Resolution Center to provide information on how these features were intended to work.
For new apps, uninstall all previous versions of your app from a device, then install and follow the steps to reproduce the issue. For updates, install the new version as an update to the previous version, then follow the steps to reproduce the issue.
收起阅读 »
项目部署到android,接口返回request:fail abort statusCode:-1
Hbuilder更新升级到2.8.2.20200726的时候,我们的项目运行到android手机就不能请求接口了
在fail的回调里面返回了‘request:fail abort statusCode:-1’; 调用后台本地连调,发现根本没有请求到接口就走了失败回调
首先我们的接口都是http和https 的,而且也没用localhost;其次也添加了sslVerify:false的参数,也还是不行
直到今天发现是manifest.josn 里 networkTimeout的问题 ,之前数值一直都写的很大一千二百万,经过我反复实验,差不多二百万内就可以,如果不写默认就是60000
没有他做不到只有我们想不到哈哈
Hbuilder更新升级到2.8.2.20200726的时候,我们的项目运行到android手机就不能请求接口了
在fail的回调里面返回了‘request:fail abort statusCode:-1’; 调用后台本地连调,发现根本没有请求到接口就走了失败回调
首先我们的接口都是http和https 的,而且也没用localhost;其次也添加了sslVerify:false的参数,也还是不行
直到今天发现是manifest.josn 里 networkTimeout的问题 ,之前数值一直都写的很大一千二百万,经过我反复实验,差不多二百万内就可以,如果不写默认就是60000
没有他做不到只有我们想不到哈哈
收起阅读 »
导入项目后 运行报getApp is not defined错误问题
对于我这边产生的原因是由于,本地项目使用Windows的目录软连接导致
对于我这边产生的原因是由于,本地项目使用Windows的目录软连接导致

uni-app极光推送 离线包和源码出售
uni-app极光推送 离线包和源码出售,有意者加QQ:543610866,注明来历
插件地址:https://ext.dcloud.net.cn/plugin?id=1009
uni-app极光推送 离线包和源码出售,有意者加QQ:543610866,注明来历
插件地址:https://ext.dcloud.net.cn/plugin?id=1009