HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

【全开源】可视化DIY微信/百度/支付宝小程序saas平台源码

百度小程序 支付宝小程序 微信小程序 小程序

多多客(doodooke)是一款支持微信、百度、支付宝小程序的第三方SaaS平台。

重要更新
1、开源diy可视化拖拉拽;
2、开源taro三端合一小程序;

3.0新特性
1、支持migrations,可以快速的创建和修改表;
2、支持rewrite,可以将请求转发到修改过的接口;
3、支持view逻辑钩子,可以扩展vue逻辑;
4、支持view视图钩子,可以扩展vue视图;
5、支持cluster,可以启动多个项目;
6、支持本地调试,可以将生产环境的请求转发或复制到本地;
7、支持bin命令,可以快速的处理migration等;

开源版下载:https://gitee.com/doodooke/doodoo
多多客演示:doodooke.com

继续阅读 »

多多客(doodooke)是一款支持微信、百度、支付宝小程序的第三方SaaS平台。

重要更新
1、开源diy可视化拖拉拽;
2、开源taro三端合一小程序;

3.0新特性
1、支持migrations,可以快速的创建和修改表;
2、支持rewrite,可以将请求转发到修改过的接口;
3、支持view逻辑钩子,可以扩展vue逻辑;
4、支持view视图钩子,可以扩展vue视图;
5、支持cluster,可以启动多个项目;
6、支持本地调试,可以将生产环境的请求转发或复制到本地;
7、支持bin命令,可以快速的处理migration等;

开源版下载:https://gitee.com/doodooke/doodoo
多多客演示:doodooke.com

收起阅读 »

【重构版教程】uni-app实战第一季:社区交友类app视频教程

入门教程 视频教程 uniapp 教程

适用人群

具备Html+Css+Javascript基础知识。

课程概述【已完结】【总共283课时】

本季度为uni-app实战项目第一季度,将实战开发社区交友类app,其中会包括发布到安卓端app,IOS端app、微信小程序和支付宝小程序。

重构版特色:

  1. 这次代码比之前少了不少,可维护性更强。
  2. 加入了vuex,过滤器等大多数用法。
  3. 大大减少view组件嵌套,提高了性能
  4. 加入更多过渡动画效果,操作更加顺畅

课程大纲见以下图!

课程学习链接入口:

uni-app实战社区交友类app开发视频教程

https://study.163.com/course/courseMain.htm?courseId=1209188809&share=2&shareId=480000001892585

或者进入网易云课堂,搜索uni-app即可看到

课程目录:(实际参考uni-app实战社区交友类app开发视频教程

继续阅读 »

适用人群

具备Html+Css+Javascript基础知识。

课程概述【已完结】【总共283课时】

本季度为uni-app实战项目第一季度,将实战开发社区交友类app,其中会包括发布到安卓端app,IOS端app、微信小程序和支付宝小程序。

重构版特色:

  1. 这次代码比之前少了不少,可维护性更强。
  2. 加入了vuex,过滤器等大多数用法。
  3. 大大减少view组件嵌套,提高了性能
  4. 加入更多过渡动画效果,操作更加顺畅

课程大纲见以下图!

课程学习链接入口:

uni-app实战社区交友类app开发视频教程

https://study.163.com/course/courseMain.htm?courseId=1209188809&share=2&shareId=480000001892585

或者进入网易云课堂,搜索uni-app即可看到

课程目录:(实际参考uni-app实战社区交友类app开发视频教程

收起阅读 »

阿萨德

work

work

dcloud.io首页滑动是否反人类?

DCloud

dcloud.io首页「他们这么说」点击左右箭头,内容滑动的方向是否反人类呢?

dcloud.io首页「他们这么说」点击左右箭头,内容滑动的方向是否反人类呢?

h5前端UDP发送经验分享,测试可用

mui.plusReady(function(){
testThread()
})
function testThread() {
var App = plus.android.runtimeMainActivity();
var Thread = plus.ios.importClass('java.lang.Thread');
var SocketChannel = plus.android.importClass('java.nio.channels.SocketChannel');
var Selector = plus.android.importClass('java.nio.channels.Selector');
var SelectionKey = plus.android.importClass('java.nio.channels.SelectionKey');
var InetSocketAddress = plus.android.importClass('java.net.InetSocketAddress');
var SocketAddress = plus.android.importClass('java.net.SocketAddress');
var ByteBuffer = plus.android.importClass('java.nio.ByteBuffer');
var Iterator = plus.android.importClass('java.util.Iterator');
var method = plus.android.importClass('java.lang.reflect.Method');
var OutputStreamWriter = plus.android.importClass('java.io.OutputStreamWriter');
//测试改良
var StrictMode = plus.android.importClass('android.os.StrictMode');
var Build = plus.android.importClass('android.os.Build');
if(Build.VERSION.SDK_INT > 9) {
var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
selectionKey = new SelectionKey();
var Runnable = plus.android.implements('java.lang.Runnable', {
"run": function() {
//选择一组键,其相应的通道已为 I/O 操作准备就绪。
//此方法执行处于阻塞模式的选择操作。
//返回此选择器的已选择键集。
var DatagramPacket = plus.android.importClass("java.net.DatagramPacket");
var DatagramSocket = plus.android.importClass("java.net.DatagramSocket");
var InetAddress = plus.android.importClass("java.net.InetAddress");
var intent = plus.android.newObject("android.content.Intent");
console.log(intent)
// InetAddress
var addr = "192.168.2.230",
port = 8080, // 60000
TTLTime = 5000;
var ia = new InetAddress();
var address = ia.getByName(addr);
console.log(address);
// socket
var socket = new DatagramSocket();
socket.setSoTimeout(TTLTime);
var data = [104, 101, 108, 108, 111];
var packet = new DatagramPacket(data, data.length, address, port);
// 发送数据
try {
socket.send(packet);
} catch(e) {
console.log(e);
}
console.log("Invoked Object’s wahaha: ");
//selectionKeys.clear();
}
});
//方式1启动线程
App.runOnUiThread(Runnable);

}

        你可以试下,我试过可以发送UDP给后台,后台能接收到信息
继续阅读 »

mui.plusReady(function(){
testThread()
})
function testThread() {
var App = plus.android.runtimeMainActivity();
var Thread = plus.ios.importClass('java.lang.Thread');
var SocketChannel = plus.android.importClass('java.nio.channels.SocketChannel');
var Selector = plus.android.importClass('java.nio.channels.Selector');
var SelectionKey = plus.android.importClass('java.nio.channels.SelectionKey');
var InetSocketAddress = plus.android.importClass('java.net.InetSocketAddress');
var SocketAddress = plus.android.importClass('java.net.SocketAddress');
var ByteBuffer = plus.android.importClass('java.nio.ByteBuffer');
var Iterator = plus.android.importClass('java.util.Iterator');
var method = plus.android.importClass('java.lang.reflect.Method');
var OutputStreamWriter = plus.android.importClass('java.io.OutputStreamWriter');
//测试改良
var StrictMode = plus.android.importClass('android.os.StrictMode');
var Build = plus.android.importClass('android.os.Build');
if(Build.VERSION.SDK_INT > 9) {
var policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
selectionKey = new SelectionKey();
var Runnable = plus.android.implements('java.lang.Runnable', {
"run": function() {
//选择一组键,其相应的通道已为 I/O 操作准备就绪。
//此方法执行处于阻塞模式的选择操作。
//返回此选择器的已选择键集。
var DatagramPacket = plus.android.importClass("java.net.DatagramPacket");
var DatagramSocket = plus.android.importClass("java.net.DatagramSocket");
var InetAddress = plus.android.importClass("java.net.InetAddress");
var intent = plus.android.newObject("android.content.Intent");
console.log(intent)
// InetAddress
var addr = "192.168.2.230",
port = 8080, // 60000
TTLTime = 5000;
var ia = new InetAddress();
var address = ia.getByName(addr);
console.log(address);
// socket
var socket = new DatagramSocket();
socket.setSoTimeout(TTLTime);
var data = [104, 101, 108, 108, 111];
var packet = new DatagramPacket(data, data.length, address, port);
// 发送数据
try {
socket.send(packet);
} catch(e) {
console.log(e);
}
console.log("Invoked Object’s wahaha: ");
//selectionKeys.clear();
}
});
//方式1启动线程
App.runOnUiThread(Runnable);

}

        你可以试下,我试过可以发送UDP给后台,后台能接收到信息
收起阅读 »

UniApp Android 仿微信 短视频拍摄 与 拍照一体插件

Android 短视频 uniapp

Android 短视频拍摄 与 拍照一体插件

参数介绍

参数名称 参数说明 默认值 类型
setMaxduration 设置最大的可录制时间(单位/秒) 10 int
setFeatures 设置拍摄模式:1=>拍照模式,2=>拍摄模式,3=> 两者都可以 3 int
setTip 设置提示文字 轻按拍照,长按录影 string
setMediaQuality 设置制视频分辨率,越大越清晰,视频也会长大 16*100000 int
setFolder 设置存储的文件夹名称 JCameraVideo string

使用方法

把插件放在根目录 nativeplugins 文件夹下,如没有则创建一个 nativeplugins 文件夹,然后直接提交云打包即可.

在需要的页面引入插件

const camera=uni.requireNativePlugin('Html5app-Camera');

如何调起拍摄

camera.open({setMaxduration:20},result=>{

this.text=JSON.stringify(result);

});

成功返回结果

参数名称 参数说明
result 返回结果 成功 "success" / 取消 "cancel"
message 提示内容
image 图片路径:包括拍摄时返回视频第一帧视频截图
mp4 视频路径
type 视频"video"" / 拍照 "image"

Android 示例扫一扫下载体验

扫一扫下载体验

短视频拍摄

HTML5+混合APP开发社区: http://www.html5-app.com/show/117

继续阅读 »

Android 短视频拍摄 与 拍照一体插件

参数介绍

参数名称 参数说明 默认值 类型
setMaxduration 设置最大的可录制时间(单位/秒) 10 int
setFeatures 设置拍摄模式:1=>拍照模式,2=>拍摄模式,3=> 两者都可以 3 int
setTip 设置提示文字 轻按拍照,长按录影 string
setMediaQuality 设置制视频分辨率,越大越清晰,视频也会长大 16*100000 int
setFolder 设置存储的文件夹名称 JCameraVideo string

使用方法

把插件放在根目录 nativeplugins 文件夹下,如没有则创建一个 nativeplugins 文件夹,然后直接提交云打包即可.

在需要的页面引入插件

const camera=uni.requireNativePlugin('Html5app-Camera');

如何调起拍摄

camera.open({setMaxduration:20},result=>{

this.text=JSON.stringify(result);

});

成功返回结果

参数名称 参数说明
result 返回结果 成功 "success" / 取消 "cancel"
message 提示内容
image 图片路径:包括拍摄时返回视频第一帧视频截图
mp4 视频路径
type 视频"video"" / 拍照 "image"

Android 示例扫一扫下载体验

扫一扫下载体验

短视频拍摄

HTML5+混合APP开发社区: http://www.html5-app.com/show/117

收起阅读 »

【精确到秒】mui 日期时间选择器修改版

mui 选择器 时间 日期

1、业务需要,需要时间选择器精确到秒,因为native模式的时间控件也只能精确到分,所以就直接对mui的日期控件稍作修改;
2、为了偷懒,就直接在mui.picker.min.js上稍加修改,并在mui.picker.min.css添加了相应的css样式(css样式也可以另外放),新增的相关代码几乎是跟秒相关的(添加的js代码,分布区域比较散而且多,所以没添加备注,可自行对比;);
3、另外,我没有改变mui日期控件type的五种类型,另外新增了一种标准格式为"年月日时分秒"的"alltime"类型。之前默认的是datetime(年月日时分),现修改为alltime类型。
4、已上传附件,可供下载体验 。

继续阅读 »

1、业务需要,需要时间选择器精确到秒,因为native模式的时间控件也只能精确到分,所以就直接对mui的日期控件稍作修改;
2、为了偷懒,就直接在mui.picker.min.js上稍加修改,并在mui.picker.min.css添加了相应的css样式(css样式也可以另外放),新增的相关代码几乎是跟秒相关的(添加的js代码,分布区域比较散而且多,所以没添加备注,可自行对比;);
3、另外,我没有改变mui日期控件type的五种类型,另外新增了一种标准格式为"年月日时分秒"的"alltime"类型。之前默认的是datetime(年月日时分),现修改为alltime类型。
4、已上传附件,可供下载体验 。

收起阅读 »

收藏一则语音api代码【来自群友:仁寿吴彦祖】

文字转语音
var text = "测试"  

uni.getSystemInfo({  
                success: res => {  
                    console.log(JSON.stringify(res.platform));  
                    if (res.platform === 'android') {  
                        _this.AndriodSpeechToVoice(text);  
                    } else if (res.platform === 'ios') {  
                        _this.iosSpeechToVoice(text);  
                    }  
                }  
            });  

//安卓文字转语音  
        AndriodSpeechToVoice: function(text) {  
            var main = plus.android.runtimeMainActivity();  
            var SpeechUtility = plus.android.importClass('com.iflytek.cloud.SpeechUtility');  
            SpeechUtility.createUtility(main, 'appid=5c2c6d5f');  
            var SynthesizerPlayer = plus.android.importClass('com.iflytek.cloud.SpeechSynthesizer');  
            var play = SynthesizerPlayer.createSynthesizer(main, null);  
            play.startSpeaking(text, null);  
        },  
        //IOS文字转语音  
        iosSpeechToVoice: function(text) {  
            var AVSpeechSynthesizer = plus.ios.importClass('AVSpeechSynthesizer');  
            var AVSpeechUtterance = plus.ios.importClass('AVSpeechUtterance');  
            var AVSpeechSynthesisVoice = plus.ios.import('AVSpeechSynthesisVoice');  
            var sppech = new AVSpeechSynthesizer();  
            var voice = AVSpeechSynthesisVoice.voiceWithLanguage('zh-CN');  
            var utterance = AVSpeechUtterance.speechUtteranceWithString(text);  
            // utterance.plusSetAttribute("rate",30.1);  
            utterance.setVoice(voice);  
            sppech.speakUtterance(utterance);  
            //停止  
            sppech.stopSpeakingAtBoundary(0);  
            //暂停  
            sppech.pauseSpeakingAtBoundary(0);  
            //继续  
            sppech.continueSpeaking(0);  
            plus.ios.deleteObject(voice);  
            plus.ios.deleteObject(utterance);  
            plus.ios.deleteObject(sppech);  
        },  
继续阅读 »
var text = "测试"  

uni.getSystemInfo({  
                success: res => {  
                    console.log(JSON.stringify(res.platform));  
                    if (res.platform === 'android') {  
                        _this.AndriodSpeechToVoice(text);  
                    } else if (res.platform === 'ios') {  
                        _this.iosSpeechToVoice(text);  
                    }  
                }  
            });  

//安卓文字转语音  
        AndriodSpeechToVoice: function(text) {  
            var main = plus.android.runtimeMainActivity();  
            var SpeechUtility = plus.android.importClass('com.iflytek.cloud.SpeechUtility');  
            SpeechUtility.createUtility(main, 'appid=5c2c6d5f');  
            var SynthesizerPlayer = plus.android.importClass('com.iflytek.cloud.SpeechSynthesizer');  
            var play = SynthesizerPlayer.createSynthesizer(main, null);  
            play.startSpeaking(text, null);  
        },  
        //IOS文字转语音  
        iosSpeechToVoice: function(text) {  
            var AVSpeechSynthesizer = plus.ios.importClass('AVSpeechSynthesizer');  
            var AVSpeechUtterance = plus.ios.importClass('AVSpeechUtterance');  
            var AVSpeechSynthesisVoice = plus.ios.import('AVSpeechSynthesisVoice');  
            var sppech = new AVSpeechSynthesizer();  
            var voice = AVSpeechSynthesisVoice.voiceWithLanguage('zh-CN');  
            var utterance = AVSpeechUtterance.speechUtteranceWithString(text);  
            // utterance.plusSetAttribute("rate",30.1);  
            utterance.setVoice(voice);  
            sppech.speakUtterance(utterance);  
            //停止  
            sppech.stopSpeakingAtBoundary(0);  
            //暂停  
            sppech.pauseSpeakingAtBoundary(0);  
            //继续  
            sppech.continueSpeaking(0);  
            plus.ios.deleteObject(voice);  
            plus.ios.deleteObject(utterance);  
            plus.ios.deleteObject(sppech);  
        },  
收起阅读 »

ios 获取idfa idfv 具体代码教程(亲测可用)

iOS IDFA

原文链接:ios 获取idfa idfv
第一步:编写manifest.json配置文件
在 manifest.json 配置文件 "ios" 下加入frameworks,以及idfa设置为真

"ios" : {
"frameworks" : [ "AdSupport.framework" ],
"idfa" : "true"
},
第二步:编辑业务代码,以下是获取idfa,idfv的函数,返回数据为json对象
getIdfa_idfv:function(){
var NSUUID = plus.ios.importClass('NSUUID');
var UIDevice = plus.ios.importClass("UIDevice");
var currentDevice = UIDevice.currentDevice()
var identifierForVendor = currentDevice.identifierForVendor().UUIDString();

var ASIdentifierManager = plus.ios.importClass("ASIdentifierManager");  
var sharedManager = ASIdentifierManager.sharedManager();  
if(sharedManager.isAdvertisingTrackingEnabled()){  
    var advertisingIdentifier = sharedManager.advertisingIdentifier();  
    var idfa = plus.ios.invoke(advertisingIdentifier,"UUIDString");   
}  
 var result = {'idfa':idfa,'idfv':identifierForVendor}  
 return result;  

}
第三步:提交打包测试
注意:不能直接使用Hbuilderx的包测试,需要使用自定义基座,或者打包测试

结果:{"idfa":"7DFFEF3C-FB3A-4121-B0D8-08F7BB0718DF","idfv":"C0EDCF46-7B3F-4AB2-BBAD-95A2FE82982E"}

继续阅读 »

原文链接:ios 获取idfa idfv
第一步:编写manifest.json配置文件
在 manifest.json 配置文件 "ios" 下加入frameworks,以及idfa设置为真

"ios" : {
"frameworks" : [ "AdSupport.framework" ],
"idfa" : "true"
},
第二步:编辑业务代码,以下是获取idfa,idfv的函数,返回数据为json对象
getIdfa_idfv:function(){
var NSUUID = plus.ios.importClass('NSUUID');
var UIDevice = plus.ios.importClass("UIDevice");
var currentDevice = UIDevice.currentDevice()
var identifierForVendor = currentDevice.identifierForVendor().UUIDString();

var ASIdentifierManager = plus.ios.importClass("ASIdentifierManager");  
var sharedManager = ASIdentifierManager.sharedManager();  
if(sharedManager.isAdvertisingTrackingEnabled()){  
    var advertisingIdentifier = sharedManager.advertisingIdentifier();  
    var idfa = plus.ios.invoke(advertisingIdentifier,"UUIDString");   
}  
 var result = {'idfa':idfa,'idfv':identifierForVendor}  
 return result;  

}
第三步:提交打包测试
注意:不能直接使用Hbuilderx的包测试,需要使用自定义基座,或者打包测试

结果:{"idfa":"7DFFEF3C-FB3A-4121-B0D8-08F7BB0718DF","idfv":"C0EDCF46-7B3F-4AB2-BBAD-95A2FE82982E"}

收起阅读 »

制作一个手机APP软件需要办理的资质证明

5+App开发

移动互联网+商业时代的井喷期已至。在你的事业蓝图中,是否早已打算好开发制作一个属于自己的APP应用平台呢?那么,在制作APP前应该有哪些准备工作,今天,力谱云就带您了解一番,制作一个手机APP软件都需要拥有哪些资质证明!

在一般情况下,如果您所开发的App,在运营过程中需要收取费用,那么您就需要为App办理网站平台经营许可证,方可进行运营。目前,主要会涉及到两种证件,ICP许可证,以及SP许可证。

1 短信服务类App
拥有经营短信、彩信、彩铃等业务的企业App;或者在新用户注册时,需要对注册用户发送验证码信息的App平台,都需要进行SP许可证的办理。

2 商城购物类App
发布商品信息,并进行交易的商城购物类App,必须拥有ICP许可证。一般可在省级通信管理局进行办理。

3 资讯/视频/图书类App
如果您所开发的App平台,在发布信息资讯、视频等信息时,需要收费,那么就需要进行ICP许可证的办理,涉及网络试听许可证、广播电视节目制作经营许可证。前者需国有控股过半,后者办理相对简单。

4 医疗资讯类App
制作移动资讯类手机App软件,目前需要互联网医疗信息服务许可证。在苹果上架时,审核过程中,有时会需要医院资质的证明文件。

5 其他类别App
一旦平台所发布的信息是有偿的,那么招聘类App、搜索类App、社交类App都会涉及到ICP许可证的办理。

总而言之,想要制作好一个付费类手机App软件,首先得知道自己的平台属于哪种范畴,需要哪些专门的资质证明。目前,力谱云团队在您开发之前,会有专人、及团队顾问,帮助您在开发前就规避一切风险,并且从研发到运营、营销,由力谱云全程保驾护航。

APP开发|APP制作|电商APP开发|APP代理加盟-力谱云-移动电商云平台

继续阅读 »

移动互联网+商业时代的井喷期已至。在你的事业蓝图中,是否早已打算好开发制作一个属于自己的APP应用平台呢?那么,在制作APP前应该有哪些准备工作,今天,力谱云就带您了解一番,制作一个手机APP软件都需要拥有哪些资质证明!

在一般情况下,如果您所开发的App,在运营过程中需要收取费用,那么您就需要为App办理网站平台经营许可证,方可进行运营。目前,主要会涉及到两种证件,ICP许可证,以及SP许可证。

1 短信服务类App
拥有经营短信、彩信、彩铃等业务的企业App;或者在新用户注册时,需要对注册用户发送验证码信息的App平台,都需要进行SP许可证的办理。

2 商城购物类App
发布商品信息,并进行交易的商城购物类App,必须拥有ICP许可证。一般可在省级通信管理局进行办理。

3 资讯/视频/图书类App
如果您所开发的App平台,在发布信息资讯、视频等信息时,需要收费,那么就需要进行ICP许可证的办理,涉及网络试听许可证、广播电视节目制作经营许可证。前者需国有控股过半,后者办理相对简单。

4 医疗资讯类App
制作移动资讯类手机App软件,目前需要互联网医疗信息服务许可证。在苹果上架时,审核过程中,有时会需要医院资质的证明文件。

5 其他类别App
一旦平台所发布的信息是有偿的,那么招聘类App、搜索类App、社交类App都会涉及到ICP许可证的办理。

总而言之,想要制作好一个付费类手机App软件,首先得知道自己的平台属于哪种范畴,需要哪些专门的资质证明。目前,力谱云团队在您开发之前,会有专人、及团队顾问,帮助您在开发前就规避一切风险,并且从研发到运营、营销,由力谱云全程保驾护航。

APP开发|APP制作|电商APP开发|APP代理加盟-力谱云-移动电商云平台

收起阅读 »

HBuilderX 重构/重命名变量/选择相同语法词/refactor/查找引用/find useage

选择相同语法词 重构 查看引用 refactor

本功能自HBuilderX 1.7.2起支持。在1.9.7中增加到了编辑器的右键菜单中。

背景

大型IDE,一般会提供重构功能,就是把一个变量/方法,重命名,这个变量的定义处和引用处都自动修改。

强类型语言都有这个功能,由于js的弱类型,这个判断很难精准。

不过HBuilderX提供了另一种安全且方便的方式,即 选择相同语法词 。

操作方法

选中一个变量(或不选,只是光标放在那里),点菜单-选择-选择相同语法词或右键菜单,win快捷键:ctrl+shift+e;mac快捷键:command+shift+e

  • 比如如下代码,光标放到变量a旁边,按下 选择相同语法词 ,效果如下:

可以看到,文档中其他的a虽然套了外框,代表有相同字符,但只有变量a的定义处和引用处,才被真正选中。

同时在状态栏可以看到,有2个选区被选中。

然后利用多光标特性,你可以自由修改a。

当然除了js变量/方法,你也可以对html的tagname、css的class执行同样的操作。

  • 比如同时选中首尾标签:

  • 比如同时选中css和html相同的id或class名称:

  • 选择相同语法词 还有一个特性,如果你选中的是一个括号,它会帮你选中另一对括号。方便同时删除一对括号。

查看引用

很多时候,我们并不是真的需要重构变量名称,只是需要查看某个变量在哪里被引用,并且在这些地方互相跳转。

方便的操作是先选中相同语法词,然后按Ctrl+F2,给这些词全部打上书签。

然后按F2可以在书签之间跳转。

不需要这些书签时,ctrl+shift+f2是清空所有书签。

局限性和使用注意

  • 由于js的弱类型,有些复杂的嵌套写法无法识别,比如eval这类方法里通过字符串表示的变量
  • css的选择器只能选中原始定义处,伪类、合并选择器的css命名,无法选中
  • 选择相同语法词 只能处理当前文档,对于跨文档的引用不处理
  • 此功能依赖语法提示插件,有些语法比如ts需要安装相应插件才可提示。对于还不能进行语法提示的语言无法使用此功能
  • 对于非常大的文档,分析时可能会有点耗时,需要耐心等待。但肯定比人工选择相同语法词快:)

如果自动选择的词不全,可以按下ctrl+鼠标双击,添加新的词到选区中。

继续阅读 »

本功能自HBuilderX 1.7.2起支持。在1.9.7中增加到了编辑器的右键菜单中。

背景

大型IDE,一般会提供重构功能,就是把一个变量/方法,重命名,这个变量的定义处和引用处都自动修改。

强类型语言都有这个功能,由于js的弱类型,这个判断很难精准。

不过HBuilderX提供了另一种安全且方便的方式,即 选择相同语法词 。

操作方法

选中一个变量(或不选,只是光标放在那里),点菜单-选择-选择相同语法词或右键菜单,win快捷键:ctrl+shift+e;mac快捷键:command+shift+e

  • 比如如下代码,光标放到变量a旁边,按下 选择相同语法词 ,效果如下:

可以看到,文档中其他的a虽然套了外框,代表有相同字符,但只有变量a的定义处和引用处,才被真正选中。

同时在状态栏可以看到,有2个选区被选中。

然后利用多光标特性,你可以自由修改a。

当然除了js变量/方法,你也可以对html的tagname、css的class执行同样的操作。

  • 比如同时选中首尾标签:

  • 比如同时选中css和html相同的id或class名称:

  • 选择相同语法词 还有一个特性,如果你选中的是一个括号,它会帮你选中另一对括号。方便同时删除一对括号。

查看引用

很多时候,我们并不是真的需要重构变量名称,只是需要查看某个变量在哪里被引用,并且在这些地方互相跳转。

方便的操作是先选中相同语法词,然后按Ctrl+F2,给这些词全部打上书签。

然后按F2可以在书签之间跳转。

不需要这些书签时,ctrl+shift+f2是清空所有书签。

局限性和使用注意

  • 由于js的弱类型,有些复杂的嵌套写法无法识别,比如eval这类方法里通过字符串表示的变量
  • css的选择器只能选中原始定义处,伪类、合并选择器的css命名,无法选中
  • 选择相同语法词 只能处理当前文档,对于跨文档的引用不处理
  • 此功能依赖语法提示插件,有些语法比如ts需要安装相应插件才可提示。对于还不能进行语法提示的语言无法使用此功能
  • 对于非常大的文档,分析时可能会有点耗时,需要耐心等待。但肯定比人工选择相同语法词快:)

如果自动选择的词不全,可以按下ctrl+鼠标双击,添加新的词到选区中。

收起阅读 »