HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

uniapp编译小程序typeof不支持的问题

uniapp

使用uniapp框架,编译后发现出现如下报错。

对 wxml 文档进行格式化,使用删代码调试的方法最终定位到了报错的内容为以下代码引起

<block wx:if="{{typeof 'a'==='string'&&item.m1==='object'}}">

再进一步排查,发现是对行内判断 typeof 不支持微信小程序造成的。

在 JavaScript 中,typeof 是一个运算符,用于返回一个表示操作数的类型的字符串。它可以用于检查一个值的数据类型,例如:

typeof 5 // 返回 "number" typeof "hello" // 返回 "string"
typeof 运算符可以用于检查任何数据类型,包括原始类型(如数字、字符串、布尔值等)和复杂类型(如对象、数组、函数等)。

然而,由于各个平台对 JavaScript 的支持情况不同,因此 UniApp 中的 JavaScript 代码并不能在所有平台上运行。例如,在微信小程序中,您可能无法使用某些 JavaScript 特性,包括行内 typeof 运算符。

最终解决办法为定义一个方法,在行内调用方法而避免直接调用 typeof。如下所示

<block wx:if="{{getType('a')==='string'&&item.m1==='object'}}">

在页面中定义函数

export default{  
  // ...  
  methods: {  
    getType(v){  
      return typeof v;  
    }  
  }  
  // ...  
}
继续阅读 »

使用uniapp框架,编译后发现出现如下报错。

对 wxml 文档进行格式化,使用删代码调试的方法最终定位到了报错的内容为以下代码引起

<block wx:if="{{typeof 'a'==='string'&&item.m1==='object'}}">

再进一步排查,发现是对行内判断 typeof 不支持微信小程序造成的。

在 JavaScript 中,typeof 是一个运算符,用于返回一个表示操作数的类型的字符串。它可以用于检查一个值的数据类型,例如:

typeof 5 // 返回 "number" typeof "hello" // 返回 "string"
typeof 运算符可以用于检查任何数据类型,包括原始类型(如数字、字符串、布尔值等)和复杂类型(如对象、数组、函数等)。

然而,由于各个平台对 JavaScript 的支持情况不同,因此 UniApp 中的 JavaScript 代码并不能在所有平台上运行。例如,在微信小程序中,您可能无法使用某些 JavaScript 特性,包括行内 typeof 运算符。

最终解决办法为定义一个方法,在行内调用方法而避免直接调用 typeof。如下所示

<block wx:if="{{getType('a')==='string'&&item.m1==='object'}}">

在页面中定义函数

export default{  
  // ...  
  methods: {  
    getType(v){  
      return typeof v;  
    }  
  }  
  // ...  
}
收起阅读 »

实现在windows、linux下上传ios app到App Store

iOS打包

实现在windows、linux下上传ios app到App Store​
我们知道发布一个app,一般是用到苹果的application loader助手上传应用,用过的都知道使用起来很繁琐,经常出错。而且只能运行在mac系统上,需要一定的硬件条件。​

前段时间发现了一个上架的辅助工具Appuploader,可以实现在windows,linux或mac上,不需要应用程序加载器和mac计算机,就可以发布app到app store,试用了下,感觉不错,分享给各位开发者,方便大家。​

Appuploader算是一个专门为IOS app上架的开发助手,可以快速,轻松地生成ios开发证书,不需要钥匙串助手; appuploader还可以批量上传屏幕截图并将ipa文件上传到Apple商店。很方便的生成证书和配置文件的,快速的上架app,提升效率的辅助工具,现在可以免费使用,分享给大家。​

继续阅读 »

实现在windows、linux下上传ios app到App Store​
我们知道发布一个app,一般是用到苹果的application loader助手上传应用,用过的都知道使用起来很繁琐,经常出错。而且只能运行在mac系统上,需要一定的硬件条件。​

前段时间发现了一个上架的辅助工具Appuploader,可以实现在windows,linux或mac上,不需要应用程序加载器和mac计算机,就可以发布app到app store,试用了下,感觉不错,分享给各位开发者,方便大家。​

Appuploader算是一个专门为IOS app上架的开发助手,可以快速,轻松地生成ios开发证书,不需要钥匙串助手; appuploader还可以批量上传屏幕截图并将ipa文件上传到Apple商店。很方便的生成证书和配置文件的,快速的上架app,提升效率的辅助工具,现在可以免费使用,分享给大家。​

收起阅读 »

hbuilder 的bug真多

HBuilderX

明明选中着项目,运行时候说没有选中,非得再点一下,点的时候又把项目折叠,还得点开,麻烦死了。

明明选中着项目,运行时候说没有选中,非得再点一下,点的时候又把项目折叠,还得点开,麻烦死了。

官方tabbar扩展、完全自定义、点击带动画效果、可设置字体粗细、隐藏图标或文本、图标或文本大小、选中和未选中的样式等等

官方tabbar扩展、完全自定义、点击带动画效果、可设置字体粗细、隐藏图标或文本、图标或文本大小、选中和未选中的样式等等:https://ext.dcloud.net.cn/plugin?id=10343

继续阅读 »

官方tabbar扩展、完全自定义、点击带动画效果、可设置字体粗细、隐藏图标或文本、图标或文本大小、选中和未选中的样式等等:https://ext.dcloud.net.cn/plugin?id=10343

收起阅读 »

在 @vue/composition-api 中使用 createSelectorQuery 的 this 问题

  • 当你在 @vue/composition-api 使用 createSelectorQuery 时获取不到 this, 则使用 getCurrentInstance 替换
  • 演示代码:
import { getCurrentInstance } from '@vue/composition-api'  

export default {  
  setup() {  
    const app = getCurrentInstance()  
    uni  
      .createSelectorQuery()  
      .in(app.proxy)  
      .select('#myCanvas')  
      .node(data => {  
        console.log(data) // 输出:{ nodeCanvasType: "2d", node: Cy }  
      })  
      .exec()  
  }  
}
  • 如果是vue3则去掉 proxy 即可
import { getCurrentInstance } from '@vue/composition-api'  

export default {  
  setup() {  
    const app = getCurrentInstance()  
    uni  
      .createSelectorQuery()  
      .in(app)  
      .select('#myCanvas')  
      .node(data => {  
        console.log(data) // 输出:{ nodeCanvasType: "2d", node: Cy }  
      })  
      .exec()  
  }  
}
继续阅读 »
  • 当你在 @vue/composition-api 使用 createSelectorQuery 时获取不到 this, 则使用 getCurrentInstance 替换
  • 演示代码:
import { getCurrentInstance } from '@vue/composition-api'  

export default {  
  setup() {  
    const app = getCurrentInstance()  
    uni  
      .createSelectorQuery()  
      .in(app.proxy)  
      .select('#myCanvas')  
      .node(data => {  
        console.log(data) // 输出:{ nodeCanvasType: "2d", node: Cy }  
      })  
      .exec()  
  }  
}
  • 如果是vue3则去掉 proxy 即可
import { getCurrentInstance } from '@vue/composition-api'  

export default {  
  setup() {  
    const app = getCurrentInstance()  
    uni  
      .createSelectorQuery()  
      .in(app)  
      .select('#myCanvas')  
      .node(data => {  
        console.log(data) // 输出:{ nodeCanvasType: "2d", node: Cy }  
      })  
      .exec()  
  }  
}
收起阅读 »

Some App Tech Support

一、软件介绍
名称:轻速云
类型:软件工具

二、功能
轻速云在线教育云平台,提供在线考试系统、在线培训系统、网上考试系统、知识竞赛等多方面的培训考试软件服务,超高并发,支持电脑、Pad和手机三端使用,并且可以实现微信考试、钉钉考试或与其他App无缝衔接,我们以更专业可靠的实力让您组织在线培训考试变得简单方便。

三、Getting Support:

邮箱: disanfang@qingsuyun.com

继续阅读 »

一、软件介绍
名称:轻速云
类型:软件工具

二、功能
轻速云在线教育云平台,提供在线考试系统、在线培训系统、网上考试系统、知识竞赛等多方面的培训考试软件服务,超高并发,支持电脑、Pad和手机三端使用,并且可以实现微信考试、钉钉考试或与其他App无缝衔接,我们以更专业可靠的实力让您组织在线培训考试变得简单方便。

三、Getting Support:

邮箱: disanfang@qingsuyun.com

收起阅读 »

VUE中定义的变量的生命期(个人测试, 如表述有误,欢迎指正)

我做了三个单元
common/myUtils.js

pages/index/index.vue (默认)

pages/page2/page2.vue

以下例子是为了证明:
这个例子,主要是证明:
1>.一个vue页面中,在script第一级中(非export),定义的变量,对自身是有效的
2>.即便这个vue页面关闭后,再打开,这个变量值仍是上次的值,
3>.如果你要避免这种情况, 你就要在onload或onshow中,初始化了一下

4>.第2个vue页面是无法访问到第1个vue页面的值(即使你已在第1页中已export了这个变量)
5>.但是,如果你在目录common中的js文件中定义了一个变量,则在vue中import一下,就可以访问\
6>.但也仅限于读取, 无法写入更改这个变量的值,
7>.如果你实在想搞个全局变量,可以用uni.setStorageSync,uni.getStorageSync来实现

common/myUtils.js

var kkkk='hello';  

export{  
  kkkk  

}
继续阅读 »

我做了三个单元
common/myUtils.js

pages/index/index.vue (默认)

pages/page2/page2.vue

以下例子是为了证明:
这个例子,主要是证明:
1>.一个vue页面中,在script第一级中(非export),定义的变量,对自身是有效的
2>.即便这个vue页面关闭后,再打开,这个变量值仍是上次的值,
3>.如果你要避免这种情况, 你就要在onload或onshow中,初始化了一下

4>.第2个vue页面是无法访问到第1个vue页面的值(即使你已在第1页中已export了这个变量)
5>.但是,如果你在目录common中的js文件中定义了一个变量,则在vue中import一下,就可以访问\
6>.但也仅限于读取, 无法写入更改这个变量的值,
7>.如果你实在想搞个全局变量,可以用uni.setStorageSync,uni.getStorageSync来实现

common/myUtils.js

var kkkk='hello';  

export{  
  kkkk  

}
收起阅读 »

plus.cache.clear实现白名单效果保存localStorage

本地存储 缓存

实现方法很简单,使用前把所有localStorage的key和值存储到两个数组,plus.cache.clear清除完成后利用循环重新写入即可

function plusReady() {  
    var key = []  
    var key_ = []  
    for (let i = 0; i < localStorage.length; i++) {  
        key.push(localStorage.key(i))  //获取所有localStorage的key  
        key_.push(localStorage.getItem(localStorage.key(i)))  //获取所有localStorage的值  
        length = localStorage.length  //获取所有localStorage数量  
        if (i == localStorage.length - 1) {  
            plus.nativeUI.confirm("确定清除缓存数据?", function (e) {  
                if (e.index == 0) {  
                    plus.cache.clear(function () { });//清除缓存  
                    plus.nativeUI.toast('已清除缓存');  
                    for (let a = 0; a < length; a++) {  
                        localStorage.setItem(key[a], key_[a])  //清除完毕后利用重新写入localStorage  
                    }  
                }  
            }, "清除缓存数据", ["确定", "取消"]);  
        }  
    }  
}  
if (window.plus) {  
    plusReady();  
} else {  
    document.addEventListener('plusready', plusReady, false);  
}
继续阅读 »

实现方法很简单,使用前把所有localStorage的key和值存储到两个数组,plus.cache.clear清除完成后利用循环重新写入即可

function plusReady() {  
    var key = []  
    var key_ = []  
    for (let i = 0; i < localStorage.length; i++) {  
        key.push(localStorage.key(i))  //获取所有localStorage的key  
        key_.push(localStorage.getItem(localStorage.key(i)))  //获取所有localStorage的值  
        length = localStorage.length  //获取所有localStorage数量  
        if (i == localStorage.length - 1) {  
            plus.nativeUI.confirm("确定清除缓存数据?", function (e) {  
                if (e.index == 0) {  
                    plus.cache.clear(function () { });//清除缓存  
                    plus.nativeUI.toast('已清除缓存');  
                    for (let a = 0; a < length; a++) {  
                        localStorage.setItem(key[a], key_[a])  //清除完毕后利用重新写入localStorage  
                    }  
                }  
            }, "清除缓存数据", ["确定", "取消"]);  
        }  
    }  
}  
if (window.plus) {  
    plusReady();  
} else {  
    document.addEventListener('plusready', plusReady, false);  
}
收起阅读 »

关于我的插件easyEcharts1.0.5更新新版本报插件名称问题

升级更新

为什么我的easy-Echarts1.0.5更新新版本一直提示下面附件的问题,单个组件已符合命名规范了。官方请告知详情

为什么我的easy-Echarts1.0.5更新新版本一直提示下面附件的问题,单个组件已符合命名规范了。官方请告知详情

分享一个苹果运行自定义基座失败终极解决方案!

本人遇到了一次苹果运行自定义基座失败的提示,如图1
不论我重启电脑、重启手机、升级手机、还是重新打包(测试UDID没有问题)均无法解决。最后使用appuploader手动将基座包安装到手机上后即可解决,希望官方也想办法解决一下!

继续阅读 »

本人遇到了一次苹果运行自定义基座失败的提示,如图1
不论我重启电脑、重启手机、升级手机、还是重新打包(测试UDID没有问题)均无法解决。最后使用appuploader手动将基座包安装到手机上后即可解决,希望官方也想办法解决一下!

收起阅读 »

如何使用 uni-app 30分钟快速开发即时通讯应用|开发者活动

即时通信 uniapp

“一套代码,多端运行”是很多开发团队的梦想,基于 uni-app 跨平台框架支持 iOS、Android、Web以及各种小程序并支持平台间互通,快速实现搭建多端即时通讯功能,降低开发难度,提升开发效率。
12月13日 晚 19:00,环信线上公开课《使用 uniapp 30分钟快速开发即时通讯应用》为题,讲解多端 uni-app 基础框架知识及搭建即时通讯功能项目实战技巧,掌握开发步骤及思路,大大增强代码复用率,提升效率。来直播间 get 环信 IM 的正确打开方式!

一、时间地点

活动时间:12 月 13 日(星期二)19:00-20:00
活动地点:线上直播

二、演讲大纲

uni-app 跨平台框架介绍
使用uni-app 生成 Android&iOS 应用
如何搭建自己的即时通讯应用
IM实战篇-uni-app 经典问题答疑
三、活动报名

报名链接:报名表单

继续阅读 »

“一套代码,多端运行”是很多开发团队的梦想,基于 uni-app 跨平台框架支持 iOS、Android、Web以及各种小程序并支持平台间互通,快速实现搭建多端即时通讯功能,降低开发难度,提升开发效率。
12月13日 晚 19:00,环信线上公开课《使用 uniapp 30分钟快速开发即时通讯应用》为题,讲解多端 uni-app 基础框架知识及搭建即时通讯功能项目实战技巧,掌握开发步骤及思路,大大增强代码复用率,提升效率。来直播间 get 环信 IM 的正确打开方式!

一、时间地点

活动时间:12 月 13 日(星期二)19:00-20:00
活动地点:线上直播

二、演讲大纲

uni-app 跨平台框架介绍
使用uni-app 生成 Android&iOS 应用
如何搭建自己的即时通讯应用
IM实战篇-uni-app 经典问题答疑
三、活动报名

报名链接:报名表单

收起阅读 »

【通知权限】app判断通知权限是否开启,前往系统设置页面开关通知权限

Push uniapp

来源:https://ext.dcloud.net.cn/plugin?id=789

// 判断通知权限是否开启  
function isOn() {  
    // #ifdef APP-PLUS  
    if (plus.os.name == 'Android') {  
        var main = plus.android.runtimeMainActivity();  
        var NotificationManagerCompat = plus.android.importClass("android.support.v4.app.NotificationManagerCompat");  
        if (NotificationManagerCompat == null) { NotificationManagerCompat = plus.android.importClass("androidx.core.app.NotificationManagerCompat"); }  
        var areNotificationsEnabled = NotificationManagerCompat.from(main).areNotificationsEnabled();  
        return areNotificationsEnabled;  
    } else if (plus.os.name == 'iOS') {  
        var isIosOn = undefined;  
        var types = 0;  
        var app = plus.ios.invoke('UIApplication', 'sharedApplication');  
        var settings = plus.ios.invoke(app, 'currentUserNotificationSettings');  
        if (settings) {  
            types = settings.plusGetAttribute('types');  
            plus.ios.deleteObject(settings);  
        } else {  
            types = plus.ios.invoke(app, 'enabledRemoteNotificationTypes');  
        }  
        plus.ios.deleteObject(app);  
        isIosOn = (0 != types);  
        return isIosOn;  
    }  
    // #endif  
}  

// 前往系统设置页面开启或关闭通知权限  
function switchPushPermissions () {  
    // #ifdef APP-PLUS  
    let title = isOn() ? "通知权限关闭提醒" : "通知权限开启提醒";  
    let content = isOn() ? "通知权限已开启,是否前往设置关闭?" : "您还没有开启通知权限,无法接受到消息通知,是否前往设置?";  
    // 打开安卓系统设置页面  
    let openAndroidSetting = () => {  
        var main = plus.android.runtimeMainActivity();  
        var pkName = main.getPackageName();  
        var uid = main.getApplicationInfo().plusGetAttribute("uid");  
        var Intent = plus.android.importClass('android.content.Intent');  
        var Build = plus.android.importClass("android.os.Build");  
        //android 8.0引导    
        if (Build.VERSION.SDK_INT >= 26) {  
            var intent = new Intent('android.settings.APP_NOTIFICATION_SETTINGS');  
            intent.putExtra('android.provider.extra.APP_PACKAGE', pkName);  
        } else if (Build.VERSION.SDK_INT >= 21) { //android 5.0-7.0    
            var intent = new Intent('android.settings.APP_NOTIFICATION_SETTINGS');  
            intent.putExtra("app_package", pkName);  
            intent.putExtra("app_uid", uid);  
        } else { //(<21)其他--跳转到该应用管理的详情页    
            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);  
            var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);  
            intent.setData(uri);  
        }  
        // 跳转到该应用的系统通知设置页    
        main.startActivity(intent);  
    }  
    // 打开苹果系统设置页面  
    let openIOSSetting = () => {  
        var app = plus.ios.invoke('UIApplication', 'sharedApplication');  
        var setting = plus.ios.invoke('NSURL', 'URLWithString:', 'app-settings:');  
        plus.ios.invoke(app, 'openURL:', setting);  
        plus.ios.deleteObject(setting);  
        plus.ios.deleteObject(app);  
    }  
    // 弹窗提醒开通或关闭权限,点击确认后,跳转到系统设置页面进行设置  
    uni.showModal({  
        title: title,  
        content: content,  
        showCancel: true,  
        confirmColor: "#ff903f",  
        success: (res) => {  
            if (res.confirm) {  
                if (plus.os.name == 'Android') {  
                    openAndroidSetting();  
                } else if (plus.os.name == 'iOS') {  
                    openIOSSetting();  
                }  
            }  
        }  
    })  
    // #endif    
}  

export default {  
    isOn,  
    switchPushPermissions  
};

↓↓↓ 各位大佬点点赞

继续阅读 »

来源:https://ext.dcloud.net.cn/plugin?id=789

// 判断通知权限是否开启  
function isOn() {  
    // #ifdef APP-PLUS  
    if (plus.os.name == 'Android') {  
        var main = plus.android.runtimeMainActivity();  
        var NotificationManagerCompat = plus.android.importClass("android.support.v4.app.NotificationManagerCompat");  
        if (NotificationManagerCompat == null) { NotificationManagerCompat = plus.android.importClass("androidx.core.app.NotificationManagerCompat"); }  
        var areNotificationsEnabled = NotificationManagerCompat.from(main).areNotificationsEnabled();  
        return areNotificationsEnabled;  
    } else if (plus.os.name == 'iOS') {  
        var isIosOn = undefined;  
        var types = 0;  
        var app = plus.ios.invoke('UIApplication', 'sharedApplication');  
        var settings = plus.ios.invoke(app, 'currentUserNotificationSettings');  
        if (settings) {  
            types = settings.plusGetAttribute('types');  
            plus.ios.deleteObject(settings);  
        } else {  
            types = plus.ios.invoke(app, 'enabledRemoteNotificationTypes');  
        }  
        plus.ios.deleteObject(app);  
        isIosOn = (0 != types);  
        return isIosOn;  
    }  
    // #endif  
}  

// 前往系统设置页面开启或关闭通知权限  
function switchPushPermissions () {  
    // #ifdef APP-PLUS  
    let title = isOn() ? "通知权限关闭提醒" : "通知权限开启提醒";  
    let content = isOn() ? "通知权限已开启,是否前往设置关闭?" : "您还没有开启通知权限,无法接受到消息通知,是否前往设置?";  
    // 打开安卓系统设置页面  
    let openAndroidSetting = () => {  
        var main = plus.android.runtimeMainActivity();  
        var pkName = main.getPackageName();  
        var uid = main.getApplicationInfo().plusGetAttribute("uid");  
        var Intent = plus.android.importClass('android.content.Intent');  
        var Build = plus.android.importClass("android.os.Build");  
        //android 8.0引导    
        if (Build.VERSION.SDK_INT >= 26) {  
            var intent = new Intent('android.settings.APP_NOTIFICATION_SETTINGS');  
            intent.putExtra('android.provider.extra.APP_PACKAGE', pkName);  
        } else if (Build.VERSION.SDK_INT >= 21) { //android 5.0-7.0    
            var intent = new Intent('android.settings.APP_NOTIFICATION_SETTINGS');  
            intent.putExtra("app_package", pkName);  
            intent.putExtra("app_uid", uid);  
        } else { //(<21)其他--跳转到该应用管理的详情页    
            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);  
            var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);  
            intent.setData(uri);  
        }  
        // 跳转到该应用的系统通知设置页    
        main.startActivity(intent);  
    }  
    // 打开苹果系统设置页面  
    let openIOSSetting = () => {  
        var app = plus.ios.invoke('UIApplication', 'sharedApplication');  
        var setting = plus.ios.invoke('NSURL', 'URLWithString:', 'app-settings:');  
        plus.ios.invoke(app, 'openURL:', setting);  
        plus.ios.deleteObject(setting);  
        plus.ios.deleteObject(app);  
    }  
    // 弹窗提醒开通或关闭权限,点击确认后,跳转到系统设置页面进行设置  
    uni.showModal({  
        title: title,  
        content: content,  
        showCancel: true,  
        confirmColor: "#ff903f",  
        success: (res) => {  
            if (res.confirm) {  
                if (plus.os.name == 'Android') {  
                    openAndroidSetting();  
                } else if (plus.os.name == 'iOS') {  
                    openIOSSetting();  
                }  
            }  
        }  
    })  
    // #endif    
}  

export default {  
    isOn,  
    switchPushPermissions  
};

↓↓↓ 各位大佬点点赞

收起阅读 »