HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

【分享】 content 和 伪元素 哪些控件不支持

<!DOCTYPE html>  
<html>  
<head>  
  <meta charset="utf-8">  
  <title>测试哪些元素支不支持伪元素</title>  
<style>  
input{  
  display: block;  
}  

body *:after{  
  content: "after";  
  color: red;  
}  

img{  
  padding:30px;  
  vertical-align: top;  
}  

</style>  
</head>  
<body>  
  <h1>测试哪些元素支不支持伪元素</h1>  
  <input type="text">  
  <input type="checkbox" name="" id="">  
  <input type="radio" name="" id="">  
  <input type="submit" value="Submit">  
  <input type="button" value="input">  
  <button>button</button>  
  <textarea name="" id="" cols="30" rows="10"></textarea>  
  <select name="" id="">  
    <option value="">select</option>  
  </select>  
  <hr>  
  <img src="https://www.baidu.com/img/bdlogo.png" alt="jb">  
  <iframe src="http://www.baidu.com" frameborder="0" width="500" height="300"></iframe>  
</body>  
</html>

text --- no
submit ---no
button --- no
textarea --- no
select ----no
img --- no
iframe -- no
=============
checkbox ----yes
radio ---- yes
button --- yes
hr --- yes
其它可以做成盒子的都支持

=============================

这个写得不全,各位需要测试的可以把这个COPY下去测试就行了。希望可以帮到大家。。。。。。。。。。。。

继续阅读 »
<!DOCTYPE html>  
<html>  
<head>  
  <meta charset="utf-8">  
  <title>测试哪些元素支不支持伪元素</title>  
<style>  
input{  
  display: block;  
}  

body *:after{  
  content: "after";  
  color: red;  
}  

img{  
  padding:30px;  
  vertical-align: top;  
}  

</style>  
</head>  
<body>  
  <h1>测试哪些元素支不支持伪元素</h1>  
  <input type="text">  
  <input type="checkbox" name="" id="">  
  <input type="radio" name="" id="">  
  <input type="submit" value="Submit">  
  <input type="button" value="input">  
  <button>button</button>  
  <textarea name="" id="" cols="30" rows="10"></textarea>  
  <select name="" id="">  
    <option value="">select</option>  
  </select>  
  <hr>  
  <img src="https://www.baidu.com/img/bdlogo.png" alt="jb">  
  <iframe src="http://www.baidu.com" frameborder="0" width="500" height="300"></iframe>  
</body>  
</html>

text --- no
submit ---no
button --- no
textarea --- no
select ----no
img --- no
iframe -- no
=============
checkbox ----yes
radio ---- yes
button --- yes
hr --- yes
其它可以做成盒子的都支持

=============================

这个写得不全,各位需要测试的可以把这个COPY下去测试就行了。希望可以帮到大家。。。。。。。。。。。。

收起阅读 »

【分享交流】h5+的Downloader下载网络图片缓存到本地的案例

downloader

之前展示图片都是通过<img src="网络图片地址"> , 每次都请求服务器, 加载比较慢;
如何做到显示图片的时候先从本地获取,没有则联网下载,缓存到本地;下次直接从本地拿,无需再联网;

看了文档,逛了论坛,没有找到现成的案例,折腾了老半天,走了好多弯路,把自己写的分享给大家,
我用Android机测试是成功的,苹果机还没有试,有问题欢迎指出:


<!DOCTYPE html>  
<html>  

    <head>  
        <meta charset="utf-8">  
        <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">  
        <meta name="apple-mobile-web-app-capable" content="yes">  
        <meta name="apple-mobile-web-app-status-bar-style" content="black">  
    </head>  

    <body>  
        <div class="mui-content">  
            <img id="img1"/>  
            <img id="img2"/>  
            <img id="img3"/>  
        </div>  
    </body>  

    <script src="../js/mui.js" type="text/javascript" charset="utf-8"></script>   
    <script type="text/javascript" charset="utf-8">  
        mui.init(); //mui初始化  
        mui.plusReady(function() {  
            setImg("img1", "http://ask.dcloud.net.cn/uploads/avatar/000/00/00/16_avatar_max.jpg");  
            setImg("img2", "http://client.bbzuche.com/resources/product/2014012094648828751145/20150611/logo.jpg");  
            setImg("img3", "http://www.bbzuche.com/images/tan.jpg");  
        });  

        /*<img>设置图片  
         *1.从本地获取,如果本地存在,则直接设置图片  
         *2.如果本地不存在则联网下载,缓存到本地,再设置图片  
         * */  
        function setImg(imgId, loadUrl) {  
                if (imgId == null || loadUrl == null) return;  
                //图片下载成功 默认保存在本地相对路径的"_downloads"文件夹里面, 如"_downloads/logo.jpg"  
                var filename = loadUrl.substring(loadUrl.lastIndexOf("/") + 1, loadUrl.length);  
                var relativePath = "_downloads/" + filename;  
                //检查图片是否已存在  
                plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {  
                    console.log("图片存在,直接设置=" + relativePath);  
                    //如果文件存在,则直接设置本地图片  
                    setImgFromLocal(imgId, relativePath);  
                }, function(e) {  
                    console.log("图片不存在,联网下载=" + relativePath);  
                    //如果文件不存在,联网下载图片  
                    setImgFromNet (imgId,loadUrl,relativePath);  
                });  
            }  

        /*给图片标签<img>设置本地图片  
         * imgId 图片标签<img>的id  
         * relativePath 本地相对路径 例如:"_downloads/logo.jpg"  
         */  
        function setImgFromLocal(imgId, relativePath) {  
                //本地相对路径("_downloads/logo.jpg")转成SD卡绝对路径("/storage/emulated/0/Android/data/io.dcloud.HBuilder/.HBuilder/downloads/logo.jpg");  
                var sd_path = plus.io.convertLocalFileSystemURL(relativePath);  
                //给<img>设置图片  
                $id(imgId).setAttribute("src", sd_path);  
            }  

        /*联网下载图片,并设置给<img>*/  
        function setImgFromNet (imgId,loadUrl,relativePath) {  
            //先设置下载中的默认图片  
            $id(imgId).setAttribute("src", "../images/loading.png");  
            //创建下载任务  
            var dtask = plus.downloader.createDownload(loadUrl, {}, function(d, status) {  
                if (status == 200) {  
                    //下载成功  
                    console.log("下载成功=" + relativePath);  
                    setImgFromLocal(imgId, d.filename);  
                } else {  
                    //下载失败,需删除本地临时文件,否则下次进来时会检查到图片已存在  
                    console.log("下载失败=" + status+"=="+relativePath);  
                    //dtask.abort();//文档描述:取消下载,删除临时文件;(但经测试临时文件没有删除,故使用delFile()方法删除);  
                    if (relativePath!=null)  
                        delFile(relativePath);  
                }  
            });  
            //启动下载任务  
            dtask.start();  
        }  

        /*删除指定文件*/  
        function delFile(relativePath) {  
            plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {  
                entry.remove(function(entry) {  
                    console.log("文件删除成功==" + relativePath);  
                }, function(e) {  
                    console.log("文件删除失败=" + relativePath);  
                });  
            });  
        }  

        /*根据id查找元素*/  
        function $id(id) {  
            return document.getElementById(id);  
        }  

    </script>  

</html>  
继续阅读 »

之前展示图片都是通过<img src="网络图片地址"> , 每次都请求服务器, 加载比较慢;
如何做到显示图片的时候先从本地获取,没有则联网下载,缓存到本地;下次直接从本地拿,无需再联网;

看了文档,逛了论坛,没有找到现成的案例,折腾了老半天,走了好多弯路,把自己写的分享给大家,
我用Android机测试是成功的,苹果机还没有试,有问题欢迎指出:


<!DOCTYPE html>  
<html>  

    <head>  
        <meta charset="utf-8">  
        <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">  
        <meta name="apple-mobile-web-app-capable" content="yes">  
        <meta name="apple-mobile-web-app-status-bar-style" content="black">  
    </head>  

    <body>  
        <div class="mui-content">  
            <img id="img1"/>  
            <img id="img2"/>  
            <img id="img3"/>  
        </div>  
    </body>  

    <script src="../js/mui.js" type="text/javascript" charset="utf-8"></script>   
    <script type="text/javascript" charset="utf-8">  
        mui.init(); //mui初始化  
        mui.plusReady(function() {  
            setImg("img1", "http://ask.dcloud.net.cn/uploads/avatar/000/00/00/16_avatar_max.jpg");  
            setImg("img2", "http://client.bbzuche.com/resources/product/2014012094648828751145/20150611/logo.jpg");  
            setImg("img3", "http://www.bbzuche.com/images/tan.jpg");  
        });  

        /*<img>设置图片  
         *1.从本地获取,如果本地存在,则直接设置图片  
         *2.如果本地不存在则联网下载,缓存到本地,再设置图片  
         * */  
        function setImg(imgId, loadUrl) {  
                if (imgId == null || loadUrl == null) return;  
                //图片下载成功 默认保存在本地相对路径的"_downloads"文件夹里面, 如"_downloads/logo.jpg"  
                var filename = loadUrl.substring(loadUrl.lastIndexOf("/") + 1, loadUrl.length);  
                var relativePath = "_downloads/" + filename;  
                //检查图片是否已存在  
                plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {  
                    console.log("图片存在,直接设置=" + relativePath);  
                    //如果文件存在,则直接设置本地图片  
                    setImgFromLocal(imgId, relativePath);  
                }, function(e) {  
                    console.log("图片不存在,联网下载=" + relativePath);  
                    //如果文件不存在,联网下载图片  
                    setImgFromNet (imgId,loadUrl,relativePath);  
                });  
            }  

        /*给图片标签<img>设置本地图片  
         * imgId 图片标签<img>的id  
         * relativePath 本地相对路径 例如:"_downloads/logo.jpg"  
         */  
        function setImgFromLocal(imgId, relativePath) {  
                //本地相对路径("_downloads/logo.jpg")转成SD卡绝对路径("/storage/emulated/0/Android/data/io.dcloud.HBuilder/.HBuilder/downloads/logo.jpg");  
                var sd_path = plus.io.convertLocalFileSystemURL(relativePath);  
                //给<img>设置图片  
                $id(imgId).setAttribute("src", sd_path);  
            }  

        /*联网下载图片,并设置给<img>*/  
        function setImgFromNet (imgId,loadUrl,relativePath) {  
            //先设置下载中的默认图片  
            $id(imgId).setAttribute("src", "../images/loading.png");  
            //创建下载任务  
            var dtask = plus.downloader.createDownload(loadUrl, {}, function(d, status) {  
                if (status == 200) {  
                    //下载成功  
                    console.log("下载成功=" + relativePath);  
                    setImgFromLocal(imgId, d.filename);  
                } else {  
                    //下载失败,需删除本地临时文件,否则下次进来时会检查到图片已存在  
                    console.log("下载失败=" + status+"=="+relativePath);  
                    //dtask.abort();//文档描述:取消下载,删除临时文件;(但经测试临时文件没有删除,故使用delFile()方法删除);  
                    if (relativePath!=null)  
                        delFile(relativePath);  
                }  
            });  
            //启动下载任务  
            dtask.start();  
        }  

        /*删除指定文件*/  
        function delFile(relativePath) {  
            plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {  
                entry.remove(function(entry) {  
                    console.log("文件删除成功==" + relativePath);  
                }, function(e) {  
                    console.log("文件删除失败=" + relativePath);  
                });  
            });  
        }  

        /*根据id查找元素*/  
        function $id(id) {  
            return document.getElementById(id);  
        }  

    </script>  

</html>  
收起阅读 »

为什么要在manifest.json中配置模块与权限

manifest

为什么要配置模块

DCloud的5+客户端对安装包的构成划分了模块,并与5+的Api接口对应,即使用了什么接口,在制作安装包时里只需将该接口对应的模块编译到安装包里即可。无关模块在最终的安装包里并不存在,如应用并未用到地图功能,则最终的安装包里不需要地图模块相关的组件。这样可以减少安装包的体积。

为什么要配置权限

Android平台对底层Api的调用做了权限控制,如要使用短信功能,需要向系统注册READ_SMS、SEND_SMS、WRITE_SMS权限。同时,应用市场对Android应用的权限会有审核,申请多余的权限可能会导致被应用市场拒收,某些特殊的权限如短信,需要额外向某些应用市场申请(参见360手机助手应用市场审核失败,提示短信权限的问题)。因此开发者需要确认自己的权限是否有多余不需要的权限。

注意若使用Native.js,如果涉及相关权限,也需要自己配置,否则打包会不能生效。

继续阅读 »

为什么要配置模块

DCloud的5+客户端对安装包的构成划分了模块,并与5+的Api接口对应,即使用了什么接口,在制作安装包时里只需将该接口对应的模块编译到安装包里即可。无关模块在最终的安装包里并不存在,如应用并未用到地图功能,则最终的安装包里不需要地图模块相关的组件。这样可以减少安装包的体积。

为什么要配置权限

Android平台对底层Api的调用做了权限控制,如要使用短信功能,需要向系统注册READ_SMS、SEND_SMS、WRITE_SMS权限。同时,应用市场对Android应用的权限会有审核,申请多余的权限可能会导致被应用市场拒收,某些特殊的权限如短信,需要额外向某些应用市场申请(参见360手机助手应用市场审核失败,提示短信权限的问题)。因此开发者需要确认自己的权限是否有多余不需要的权限。

注意若使用Native.js,如果涉及相关权限,也需要自己配置,否则打包会不能生效。

收起阅读 »

常见问题整理

HBuilder

querySelectorAll的结果遍历时对象为空

document.querySelectorAll(".box")得到的不是数组,是nodelist,虽然可以类似数组的for,但真的不是数组,不能直接对其使用数组的方法forEach,如果我们需要转换为数组,我们可以用Array.prototype.slice.call来辅助就可以了。

https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/

var divs = document.querySelectorAll('div');  

[].forEach.call(divs, function(div) {  
  // do whatever  
  div.style.color = "red";  
});

Android平台通过native.js实现接收系统消息,如监听安装卸载apk事件

http://ask.dcloud.net.cn/article/222

继续阅读 »

querySelectorAll的结果遍历时对象为空

document.querySelectorAll(".box")得到的不是数组,是nodelist,虽然可以类似数组的for,但真的不是数组,不能直接对其使用数组的方法forEach,如果我们需要转换为数组,我们可以用Array.prototype.slice.call来辅助就可以了。

https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/

var divs = document.querySelectorAll('div');  

[].forEach.call(divs, function(div) {  
  // do whatever  
  div.style.color = "red";  
});

Android平台通过native.js实现接收系统消息,如监听安装卸载apk事件

http://ask.dcloud.net.cn/article/222

收起阅读 »

plus.webview.create 跟 mui.openWindow有什么区别?

mui Webview

openwindow 是对5+的封装,更细致的操作用plus.webview相关方法

@Ting

openwindow 是对5+的封装,更细致的操作用plus.webview相关方法

@Ting

底部导航菜单切换,并返回首页的实现

mui

实现nav导航,与子页面切换
文档参考:http://dcloudio.github.io/mui/javascript/#subpage

在html添加数个导航,在js中,为这些导航批量添加事件,在点击的时候打开子页面。子页面无底部导航,共用父页面的底部导航。
父子页面共用底部导航,在预加载的地方,使用styles.bottom即可

复杂的地方在于,切换为首页时,要保持首页的状态,则需要显示应用初始化时候的状态,则需要找到当前父页面的id并进行展示

        $.page_nav = function() {  
            navs = document.querySelectorAll(".mui-tab-item");  
            for(n in navs)  
            {  
                obj = navs[n] .getAttributeNode("id").value;  
                app_debug && console.log(obj);  

                if(obj != 'page_index') {  
                    $.preload({  
                        "id": obj,  
                        "url": obj.replace("page_", "")+'.html',  
                        "styles":{  
                            top:'0px',//mui标题栏默认高度为45px  
                            bottom: '50px',//mui导航栏默认高度为50px  
                        }  
                    });  
                }  

                document.getElementById(obj).addEventListener("tap", function(){  
                    if(this.id == 'page_index') {  
                        //获得主页面的webview  
                        var main = plus.webview.currentWebview();  
                        mui.openWindow({"id":main.id});  
                    } else {  
                        mui.openWindow({  
                            "id":this.id,  
                            "crateNew":false,  
                            "styles":{  
                                top:'0px',//mui标题栏默认高度为45px  
                                bottom: '50px'//默认为0px,可不定义  
                            }  
                        });  
                    }  
                }, false);  
            }  
        }  

        //底部导航菜单绑定  
        $.page_nav();
    <nav class="mui-bar mui-bar-tab">  
        <a class="mui-tab-item mui-active" id="page_index" target="index.html">  
            <span class="mui-icon icon iconfont icon-beauty">&#xe600;</span>  
            <span class="mui-tab-label">清新</span>  
        </a>  
        <a class="mui-tab-item" id="page_category" target="category.html">  
            <span class="mui-icon iconfont icon-sexy">&#xe601;</span>  
            <span class="mui-tab-label">时尚</span>  
        </a>  
        <a class="mui-tab-item" id="page_article" target="article.html">  
            <span class="mui-icon iconfont icon-meng">&#xe602;</span>  
            <span class="mui-tab-label">评论</span>  
        </a>  
        <a class="mui-tab-item" id="page_login" target="login.html">  
            <span class="mui-icon mui-icon-gear"></span>  
            <span class="mui-tab-label">设置</span>  
        </a>  
    </nav>
继续阅读 »

实现nav导航,与子页面切换
文档参考:http://dcloudio.github.io/mui/javascript/#subpage

在html添加数个导航,在js中,为这些导航批量添加事件,在点击的时候打开子页面。子页面无底部导航,共用父页面的底部导航。
父子页面共用底部导航,在预加载的地方,使用styles.bottom即可

复杂的地方在于,切换为首页时,要保持首页的状态,则需要显示应用初始化时候的状态,则需要找到当前父页面的id并进行展示

        $.page_nav = function() {  
            navs = document.querySelectorAll(".mui-tab-item");  
            for(n in navs)  
            {  
                obj = navs[n] .getAttributeNode("id").value;  
                app_debug && console.log(obj);  

                if(obj != 'page_index') {  
                    $.preload({  
                        "id": obj,  
                        "url": obj.replace("page_", "")+'.html',  
                        "styles":{  
                            top:'0px',//mui标题栏默认高度为45px  
                            bottom: '50px',//mui导航栏默认高度为50px  
                        }  
                    });  
                }  

                document.getElementById(obj).addEventListener("tap", function(){  
                    if(this.id == 'page_index') {  
                        //获得主页面的webview  
                        var main = plus.webview.currentWebview();  
                        mui.openWindow({"id":main.id});  
                    } else {  
                        mui.openWindow({  
                            "id":this.id,  
                            "crateNew":false,  
                            "styles":{  
                                top:'0px',//mui标题栏默认高度为45px  
                                bottom: '50px'//默认为0px,可不定义  
                            }  
                        });  
                    }  
                }, false);  
            }  
        }  

        //底部导航菜单绑定  
        $.page_nav();
    <nav class="mui-bar mui-bar-tab">  
        <a class="mui-tab-item mui-active" id="page_index" target="index.html">  
            <span class="mui-icon icon iconfont icon-beauty">&#xe600;</span>  
            <span class="mui-tab-label">清新</span>  
        </a>  
        <a class="mui-tab-item" id="page_category" target="category.html">  
            <span class="mui-icon iconfont icon-sexy">&#xe601;</span>  
            <span class="mui-tab-label">时尚</span>  
        </a>  
        <a class="mui-tab-item" id="page_article" target="article.html">  
            <span class="mui-icon iconfont icon-meng">&#xe602;</span>  
            <span class="mui-tab-label">评论</span>  
        </a>  
        <a class="mui-tab-item" id="page_login" target="login.html">  
            <span class="mui-icon mui-icon-gear"></span>  
            <span class="mui-tab-label">设置</span>  
        </a>  
    </nav>
收起阅读 »

挑食火锅公司招聘HTML5工程师【加急】

招聘

公司介绍:

挑食是一家专业火锅上门服务的O2O公司,从去年10月推出,已经获得两轮融资,投资人中包括薛蛮子、蒋涛、王峰等知名人士,短短半年时间已做到火锅上门第一大,服务了数万家庭火锅用餐。已开通北上广深四地业务,现急需高端技术人才加入

招人需求:

  1. 吃货;
  2. 年轻,能折腾,爱扣爱钻研;
  3. 精通web前端开发技术;
  4. 良好的代码书写风格和交流能力;
  5. 开发过mobile webApp和微信App优先;
  6. 熟悉HBuilder、5+、mui优先;

职责:

使用HBuilder开发5+ App、微信App、网站

薪资:

15-25k

工作地点:

北京朝阳区常营

有意速投简历到dougaofeng@mobyeah.com,
不投简历的也可以关注微信公众号tiaoshicom,订个火锅送上门!

继续阅读 »

公司介绍:

挑食是一家专业火锅上门服务的O2O公司,从去年10月推出,已经获得两轮融资,投资人中包括薛蛮子、蒋涛、王峰等知名人士,短短半年时间已做到火锅上门第一大,服务了数万家庭火锅用餐。已开通北上广深四地业务,现急需高端技术人才加入

招人需求:

  1. 吃货;
  2. 年轻,能折腾,爱扣爱钻研;
  3. 精通web前端开发技术;
  4. 良好的代码书写风格和交流能力;
  5. 开发过mobile webApp和微信App优先;
  6. 熟悉HBuilder、5+、mui优先;

职责:

使用HBuilder开发5+ App、微信App、网站

薪资:

15-25k

工作地点:

北京朝阳区常营

有意速投简历到dougaofeng@mobyeah.com,
不投简历的也可以关注微信公众号tiaoshicom,订个火锅送上门!

收起阅读 »

北京卡拉丁公司招聘HTML5工程师

招聘

公司介绍:

卡拉丁是一家面向广大汽车用户提供便捷养护服务的创新型汽车后市场O2O服务提供商。公司网站www.kalading.com
卡拉丁目前在北京、上海和天津等十多个城市为用户提供上门汽车保养服务。 “便捷、透明、安全”就是卡拉丁的产品理念,通过养护技术与服务方式的创新,并结合移动互联网技术,卡拉丁最先提出并实现了规模化、标准化的上门汽车保养服务。公司2015年4月完成由宽带资本领投的千万美元A轮融资。请不要错过加入未来能够改变汽车服务行业成为互联网巨头职员的机会!

招人需求:

html5/JS/Rails高级工程师,
有兴趣同时做web前端和后端开发,
喜欢Ruby,喜欢javascript语言,
熟悉rails,mongodb,bootstrap,angularjs者优先。

职责:

开发基于rails,移动设备优先的网站。

薪资:

20-25K

欢迎投递简历到633@kalading.com

继续阅读 »

公司介绍:

卡拉丁是一家面向广大汽车用户提供便捷养护服务的创新型汽车后市场O2O服务提供商。公司网站www.kalading.com
卡拉丁目前在北京、上海和天津等十多个城市为用户提供上门汽车保养服务。 “便捷、透明、安全”就是卡拉丁的产品理念,通过养护技术与服务方式的创新,并结合移动互联网技术,卡拉丁最先提出并实现了规模化、标准化的上门汽车保养服务。公司2015年4月完成由宽带资本领投的千万美元A轮融资。请不要错过加入未来能够改变汽车服务行业成为互联网巨头职员的机会!

招人需求:

html5/JS/Rails高级工程师,
有兴趣同时做web前端和后端开发,
喜欢Ruby,喜欢javascript语言,
熟悉rails,mongodb,bootstrap,angularjs者优先。

职责:

开发基于rails,移动设备优先的网站。

薪资:

20-25K

欢迎投递简历到633@kalading.com

收起阅读 »

关于HTML、js加密、混淆、源码保护、代码安全,防止解压直接看源码

防调试 混淆 加壳 加固 代码保护 安全 加密

更新:HBuilderX下,包括5+app和uni-app的使用方式,另见文章https://ask.dcloud.net.cn/article/36437`

================以下文章是老HBuilder的加密介绍====================

一直有人问HTML加密混淆怎么做,其实这在业内是早已很多人研究过的课题。
假日期间整理一篇文章分享给大家。

我们先理下需求,加密的目的是什么?加密到什么级别?为此我们可以牺牲什么?
我们知道这个世界不存在绝对的安全,加密会被破解、混淆会被反混淆。
技术小白、开发者、黑客,是完全不同的级别,防范不同级别的人策略都不一样。
防范力度越大,投入代价也越大,比如聘请专业的安全公司。
除了投入,我们还需要考虑程序的执行性能和用户体验。
加密的代码在运行时必须解密,混淆后尤其是混淆HTML后,程序的执行性能会下降。
是否真的有必要做这类的源码保护,还需要谨慎取舍。

一般而言,前端的代码,负责的是用户体验,后端的代码,负责更安全的数据处理。
前端不要涉及泄漏太多涉密信息,那么加密的意义不是特别大。
我很少在前端代码里看到值得保护的内容,比如高深的算法,很多代码是没必要牺牲用户体验来保护的。
但有些前端代码涉及最终用户的数据安全,此时还是要努力做数据保护的。

接下来具体分析几种手段。

  1. 不要在前端放敏感数据
    这个听起来是废话,但真的很重要。
    有些开发者在手机端明文存用户的密码,这是非常危险的事情。
    即使是原生开发,一旦手机被root,也会造成数据泄漏。更何况HTML5开发。
    比较好的做法是手机端存token,而不是密码,这里有篇文章专门介绍这块,涉及做登录的开发者推荐仔细看看设计基于HTML5的APP登录功能及安全调用接口的方式(原理篇)

  2. js、css压缩
    压缩不是加密,也不是混淆。但压缩后的js文件,往往也具有混淆的功能。
    js、css压缩是很常见的技术,我们经常看到各种框架的文件名是xxx.min.js,xxx.min.css。
    使用合适的js、css压缩方案,可以减少文件体积、提高载入速度,最重要的是,它还能加快程序的执行性能。简直是有百利而无一害。
    压缩js比较常用的工具是yahoo的YUI混淆,在HBuilder里点菜单工具-插件安装,里面有YUI compress,可以压缩js和css。
    如果js、css比较大,发布前压缩下是比较推荐的做法。

  3. HTML、js、css混淆
    压缩虽然也能混淆,但不是以让别人看不懂为目的,混淆是真正以别人看不懂为目的。
    但是这样的混淆就不像压缩那么有百利而无一害了,它会降低程序执行性能。
    一些开发者不希望发行包解压后可以直接看到源码,那么此时可以使用混淆方案。
    网上搜索HTML混淆,资料和工具都非常多。
    原理都是类似的,js代码变成乱七八糟的字符串,然后用eval执行,HTML代码变乱七八糟字符串,用document.write或innerHTML执行,css也可以动态的在document.write里写<style>。
    这些工具有免费也有商业的,一般越商业的越难被反混淆。
    这个是免费的在线混淆工具 http://www.myobfuscate.com
    这个是比较知名的商业工具,http://www.jasob.com
    其实大家也可以根据原理自己写混淆算法。
    混淆也是一个有年头的成熟技术,比如Google在保护gmail的前端代码时,也是通过混淆来保护的。
    不管是压缩还是混淆,使用grunt来做发布是不错的方式,开发后一键调用grunt处理,非常便捷。
    HBuilder在原生层面支持js混淆,性能高于前端混淆。详情下面第6点。

    这篇文章对于前端的代码保护也讲的非常专业,值得大家学习http://div.io/topic/1220

  4. 防止webkit remote debug,即防止浏览器控制台调试
    Android4.4及以上和iOS是支持webkit remote debug的,在HBuilder的教程里也有如何使用chrome调试Android应用,和使用safari调试iOS应用的教程。
    在HBuilder开发的App里,manifest.json里下的plus-distribute下有一个debug标签,标记为false后打包(可视化界面里也有配置),这样的包运行在手机上时webview会阻止浏览器的远程调试请求。
    如果你想调试,那么把debug改为true后再打包。
    当然有些Android rom不是很规范,并不能阻止调试,这属于rom的bug。
    另外注意只有打包才能防调试,真机运行是不能阻止调试的。

  5. 专业加密加固加壳服务
    由于Android的特殊性,针对apk出现了加固、加壳产业,这也是业内常见的apk保护方案。
    很多应用市场都提供加固服务,比如360手机助手的加固。
    还有一批专业公司如爱加密,里面有免费的基础安全保障服务,也有收费的高级安全保障服务。
    这里还有一个防止apk解压的小技巧:http://www.52pojie.cn/thread-287242-1-1.html

  6. HBuilder提供的原生js混淆
    在HBuilder或HBuilderX中,官方提供了原生层面的js混淆。
    这种混淆的性能比纯前端混淆的性能要更好,反编译的难度也更大。但有些限制和使用注意:

    1. Android4以下的手机不能运行加密后的js。
    2. 5+App下,iOS若配置wkWebview,则不能运行加密后的js。
      具体使用方式是在打包界面,可以选择需要加密的js文件,然后打包即可。如下图:
继续阅读 »

更新:HBuilderX下,包括5+app和uni-app的使用方式,另见文章https://ask.dcloud.net.cn/article/36437`

================以下文章是老HBuilder的加密介绍====================

一直有人问HTML加密混淆怎么做,其实这在业内是早已很多人研究过的课题。
假日期间整理一篇文章分享给大家。

我们先理下需求,加密的目的是什么?加密到什么级别?为此我们可以牺牲什么?
我们知道这个世界不存在绝对的安全,加密会被破解、混淆会被反混淆。
技术小白、开发者、黑客,是完全不同的级别,防范不同级别的人策略都不一样。
防范力度越大,投入代价也越大,比如聘请专业的安全公司。
除了投入,我们还需要考虑程序的执行性能和用户体验。
加密的代码在运行时必须解密,混淆后尤其是混淆HTML后,程序的执行性能会下降。
是否真的有必要做这类的源码保护,还需要谨慎取舍。

一般而言,前端的代码,负责的是用户体验,后端的代码,负责更安全的数据处理。
前端不要涉及泄漏太多涉密信息,那么加密的意义不是特别大。
我很少在前端代码里看到值得保护的内容,比如高深的算法,很多代码是没必要牺牲用户体验来保护的。
但有些前端代码涉及最终用户的数据安全,此时还是要努力做数据保护的。

接下来具体分析几种手段。

  1. 不要在前端放敏感数据
    这个听起来是废话,但真的很重要。
    有些开发者在手机端明文存用户的密码,这是非常危险的事情。
    即使是原生开发,一旦手机被root,也会造成数据泄漏。更何况HTML5开发。
    比较好的做法是手机端存token,而不是密码,这里有篇文章专门介绍这块,涉及做登录的开发者推荐仔细看看设计基于HTML5的APP登录功能及安全调用接口的方式(原理篇)

  2. js、css压缩
    压缩不是加密,也不是混淆。但压缩后的js文件,往往也具有混淆的功能。
    js、css压缩是很常见的技术,我们经常看到各种框架的文件名是xxx.min.js,xxx.min.css。
    使用合适的js、css压缩方案,可以减少文件体积、提高载入速度,最重要的是,它还能加快程序的执行性能。简直是有百利而无一害。
    压缩js比较常用的工具是yahoo的YUI混淆,在HBuilder里点菜单工具-插件安装,里面有YUI compress,可以压缩js和css。
    如果js、css比较大,发布前压缩下是比较推荐的做法。

  3. HTML、js、css混淆
    压缩虽然也能混淆,但不是以让别人看不懂为目的,混淆是真正以别人看不懂为目的。
    但是这样的混淆就不像压缩那么有百利而无一害了,它会降低程序执行性能。
    一些开发者不希望发行包解压后可以直接看到源码,那么此时可以使用混淆方案。
    网上搜索HTML混淆,资料和工具都非常多。
    原理都是类似的,js代码变成乱七八糟的字符串,然后用eval执行,HTML代码变乱七八糟字符串,用document.write或innerHTML执行,css也可以动态的在document.write里写<style>。
    这些工具有免费也有商业的,一般越商业的越难被反混淆。
    这个是免费的在线混淆工具 http://www.myobfuscate.com
    这个是比较知名的商业工具,http://www.jasob.com
    其实大家也可以根据原理自己写混淆算法。
    混淆也是一个有年头的成熟技术,比如Google在保护gmail的前端代码时,也是通过混淆来保护的。
    不管是压缩还是混淆,使用grunt来做发布是不错的方式,开发后一键调用grunt处理,非常便捷。
    HBuilder在原生层面支持js混淆,性能高于前端混淆。详情下面第6点。

    这篇文章对于前端的代码保护也讲的非常专业,值得大家学习http://div.io/topic/1220

  4. 防止webkit remote debug,即防止浏览器控制台调试
    Android4.4及以上和iOS是支持webkit remote debug的,在HBuilder的教程里也有如何使用chrome调试Android应用,和使用safari调试iOS应用的教程。
    在HBuilder开发的App里,manifest.json里下的plus-distribute下有一个debug标签,标记为false后打包(可视化界面里也有配置),这样的包运行在手机上时webview会阻止浏览器的远程调试请求。
    如果你想调试,那么把debug改为true后再打包。
    当然有些Android rom不是很规范,并不能阻止调试,这属于rom的bug。
    另外注意只有打包才能防调试,真机运行是不能阻止调试的。

  5. 专业加密加固加壳服务
    由于Android的特殊性,针对apk出现了加固、加壳产业,这也是业内常见的apk保护方案。
    很多应用市场都提供加固服务,比如360手机助手的加固。
    还有一批专业公司如爱加密,里面有免费的基础安全保障服务,也有收费的高级安全保障服务。
    这里还有一个防止apk解压的小技巧:http://www.52pojie.cn/thread-287242-1-1.html

  6. HBuilder提供的原生js混淆
    在HBuilder或HBuilderX中,官方提供了原生层面的js混淆。
    这种混淆的性能比纯前端混淆的性能要更好,反编译的难度也更大。但有些限制和使用注意:

    1. Android4以下的手机不能运行加密后的js。
    2. 5+App下,iOS若配置wkWebview,则不能运行加密后的js。
      具体使用方式是在打包界面,可以选择需要加密的js文件,然后打包即可。如下图:
收起阅读 »

菜鸟福利-----以有道翻译API为例说明mui ajax的用法详解

跨域请求 ajax

第一步:在有道官方网站申请一个API key

举例:
API key:1207861310
keyfrom:abc1243
调用说明:
http://fanyi.youdao.com/openapi.do?keyfrom=<keyfrom>&key=<key>&type=data&doctype=<doctype>&version=1.1&q=要翻译的文本
版本:1.1,请求方式:get,编码方式:utf-8
主要功能:中英互译,同时获得有道翻译结果和有道词典结果(可能没有)
参数说明:

  • type - 返回结果的类型,固定为data
  • doctype - 返回结果的数据格式,xml或json或jsonp
  • version - 版本,当前最新版本为1.1
  • q - 要翻译的文本,必须是UTF-8编码,字符长度不能超过200个字符,需要进行urlencode编码
  • only - 可选参数,dict表示只获取词典数据,translate表示只获取翻译数据,默认为都获取

 注: 词典结果只支持中英互译,翻译结果支持英日韩法俄西到中文的翻译以及中文到英语的翻译

errorCode:

  • 0 - 正常
  • 20 - 要翻译的文本过长
  • 30 - 无法进行有效的翻译
  • 40 - 不支持的语言类型
  • 50 - 无效的key
  • 60 - 无词典结果,仅在获取词典结果生效
     
    注意修改标记的四个地方,只需要修改q的值为你想要的翻译内容即可。

点击下方链接我们可以得到:
http://fanyi.youdao.com/openapi.do?keyfrom=abc1243&key=1207861310&type=data&doctype=json&version=1.1&q=翻译

可是网上多半就停留在此并没有告诉我们怎么在程序里面发出请求然后获取数据,之前找过一些例子,都是服务器端语言调用的,所以我误以为只能通过服务器端语言才能调用,结果一次在群里问了问,一个大神告诉说其实ajax就可以咯,于是之间就去找了找ajax的教程看了看,但是没怎么看懂,一大堆什么XMLHttpRequest 什么的,试了试还是各种理不清,找官方demo改了改,发现mui的ajax还是挺好懂的,格式也比较固定,对于菜鸟的我来说感觉这个才是最好的,不要先来一大堆没用的,废话少说,试试看就知道咯。

第二步:ajax跨域请求的简单实例

先来个最简单的直接点击按钮弹出返回的数据,只要这个成功了,那么改改还是很容易的。
【html部分】:

 <button type="button" id="confirm" class="mui-btn mui-btn-royal mui-btn-block">发送请求</button>

【js部分】:

<script src="js/mui.min.js"></script>  
<script>  
    //发送请求按钮的点击事件  
    document.getElementById("confirm").addEventListener('tap', function() {  
        var url = "http://fanyi.youdao.com/openapi.do?keyfrom=abc1243&key=1207861310&type=data&doctype=json&version=1.1&q=good";  
        mui.ajax(url,{  
            dataType:'json',//服务器返回json格式数据  
            type:'GET',//HTTP请求类型  
            timeout:10000,//超时时间设置为10秒;  
            success:function(data){  
                //JSON.stringify()将 JSON对象转为json字符串   
                var data = JSON.stringify(data);  
                alert(data);  
            },  
            error:function(xhr,type,errorThrown){  
                //异常处理;  
                console.log(type);  
            }  
        });  
    });  
</script>

第三步:传递参数的ajax跨域请求

上面URL中把各种请求参数写固定了,不便于我们后期做修改,现在用ajax的data属性。
首先我们增加一个搜索输入框用于输入要翻译的内容:
修改html的代码如下:(样式文件没有引入,样式也没有写出来,主要是为了写清楚思路)
【html部分】

<form name="search" method="get">  
        <div class="mui-input-row mui-search input-search">  
        <input type="search" id="search"  class="mui-input-speech mui-input-clear" placeholder="请输入内容...">  
        </div>  
        <button type="button" id="confirm" class="mui-btn mui-btn-royal mui-btn-block">发送请求</button>  
</form> 

【js部分】(修改部分的代码)

var search = document.getElementById("search");  
//发送请求按钮的点击事件  
document.getElementById("confirm").addEventListener('tap', function() {  
    var url = "http://fanyi.youdao.com/openapi.do";  
    mui.ajax(url,{  
        data:{  
            keyfrom:"abc1243",  
            key:"1207861310",  
            type:"data",  
            doctype:"json",  
            version:"1.1",  
            q:search.value  
        },  
        dataType:'json',//服务器返回json格式数据  
        type:'post',//HTTP请求类型  
        timeout:10000,//超时时间设置为10秒;  
        success:function(data){  
            //JSON.stringify()将 JSON对象转为json字符串   
            var data = JSON.stringify(data);  
            alert(data);  
        },  
        error:function(xhr,type,errorThrown){  
            //异常处理;  
            console.log(type);  
        }  
    });  
});

第四步:ajax跨域请求怎么处理获取的数据

我们刚刚只是把数据alert出来了但是并没有进行任何后期操作,比如把有用信息获取写出来。
我们是把刚刚那个变成了json字符串alert出来的,也就是说是字符串而不是对象,获取键值对必须是对对象进行操作。
那么我们首先使用eval函数把json字符串转化成JavaScript对象:

//将json字符串转化成JavaScript对象  
var obj = eval ("(" + response + ")");

然后我们就可以对obj对象进行操作了,json键值对的[] 中括号的使用如下:
JSON就是一串字符串 只不过元素会使用特定的符号标注。

  • {} 双括号表示对象
  • [] 中括号表示数组
  • "" 双引号内是属性或值
  • : 冒号表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)
    所以 {"name": "Michael"} 可以理解为是一个包含name为Michael的对象,而[{"name": "Michael"},{"name": "Jerry"}]就表示包含两个对象的数组。
    var LangShen = {"Name":"Langshen","AGE":"28"};
      这是一个json对象;{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数上面声明了一个名为“LangShen”的对象,多个属性或函数用,(逗号)隔开,因为是对象的属性,
      那么我们访问的时候会有两种方式:
    访问方式一:LangShen.Name、LangShen.AGE
      访问方式二:LangShen["Name"]、LangShen["AGE"]
      就是这么一个小小的方式,会有什么区别呢?
      在实际应用中,第一种方式的.Name实际是作为一个对象被调用,而LangShen["Name"]里的name却可以是一个字符串。
    有道翻译API获取实例:

我只是写出了基本思路,无非就是把对于内容写在对应的位置。

document.getElementById("translation").innerHTML=obj.translation;   
document.getElementById("us-phonetic").innerHTML=obj.basic["us-phonetic"];  
document.getElementById("phonetic").innerHTML=obj.basic["phonetic"];  
document.getElementById("uk-phonetic").innerHTML=obj.basic["uk-phonetic"];  
document.getElementById("explains").innerHTML=obj.basic["explains"];  
document.getElementById("query").innerHTML=obj.query;  
//遍历读取键值对写入  
for(var str in obj.web){  
     var keyid=document.getElementsByName("webkey")[str].id;  
     var Valueid=document.getElementsByName("webvalue")[str].id;  
     document.getElementById(keyid).innerHTML=obj.web[str]["key"];  
     document.getElementById(Valueid).innerHTML=obj.web[str]["value"];  
}   

如果需要在普通页面使用,可以使用jsonp:

<!doctype html>  
<html>  

    <head>  
        <meta charset="UTF-8">  
        <title></title>  
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
        <link href="css/mui.min.css" rel="stylesheet" />  
    </head>  
    <body>  
        <header class="mui-bar mui-bar-nav">  
            <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>  
            <h1 class="mui-title">native-JavaScript</h1>  
        </header>  
        <div class="mui-content mui-content-padded">  
            <div class="mui-input-row">  
                <label>输入关键词:</label>  
                <input id="input" type="text" placeholder="普通输入框">  
            </div>  
            <button id="btn" type="button" class="mui-btn mui-btn-blue mui-btn-block">翻译</button>  
            <div id="output"></div>  
        </div>  

        <script type="text/javascript">  
            var inputEl = document.querySelector("#input");  
            document.querySelector('#btn').addEventListener('click',function () {  
                var url = "http://fanyi.youdao.com/openapi.do";  
                var data = {  
                    "keyfrom": "abc1243",  
                    "key": "1207861310",  
                    "type": "data",  
                    "doctype": "jsonp",  
                    "version": "1.1",  
                    "q": inputEl.value,  
                    "callback": "jsonpcallback"  
                }  

                var buffer = [];  
                for (var key in data) {  
                    buffer.push(key + '=' + encodeURIComponent(data[key]));  
                }  
                var fullpath = url + '?' + buffer.join('&');  
                CreateScript(fullpath);     
            })  

            function CreateScript(src){  
                var el = document.createElement('script');  
                el.src = src;  
                el.async = true;  
                el.defer = true;  
                document.body.appendChild(el);  
            }  

            function jsonpcallback(rs) {  
                console.log(JSON.stringify(rs));  
                document.getElementById("output").innerHTML = JSON.stringify(rs);  
            }  
        </script>  
    </body>  

</html>
继续阅读 »

第一步:在有道官方网站申请一个API key

举例:
API key:1207861310
keyfrom:abc1243
调用说明:
http://fanyi.youdao.com/openapi.do?keyfrom=<keyfrom>&key=<key>&type=data&doctype=<doctype>&version=1.1&q=要翻译的文本
版本:1.1,请求方式:get,编码方式:utf-8
主要功能:中英互译,同时获得有道翻译结果和有道词典结果(可能没有)
参数说明:

  • type - 返回结果的类型,固定为data
  • doctype - 返回结果的数据格式,xml或json或jsonp
  • version - 版本,当前最新版本为1.1
  • q - 要翻译的文本,必须是UTF-8编码,字符长度不能超过200个字符,需要进行urlencode编码
  • only - 可选参数,dict表示只获取词典数据,translate表示只获取翻译数据,默认为都获取

 注: 词典结果只支持中英互译,翻译结果支持英日韩法俄西到中文的翻译以及中文到英语的翻译

errorCode:

  • 0 - 正常
  • 20 - 要翻译的文本过长
  • 30 - 无法进行有效的翻译
  • 40 - 不支持的语言类型
  • 50 - 无效的key
  • 60 - 无词典结果,仅在获取词典结果生效
     
    注意修改标记的四个地方,只需要修改q的值为你想要的翻译内容即可。

点击下方链接我们可以得到:
http://fanyi.youdao.com/openapi.do?keyfrom=abc1243&key=1207861310&type=data&doctype=json&version=1.1&q=翻译

可是网上多半就停留在此并没有告诉我们怎么在程序里面发出请求然后获取数据,之前找过一些例子,都是服务器端语言调用的,所以我误以为只能通过服务器端语言才能调用,结果一次在群里问了问,一个大神告诉说其实ajax就可以咯,于是之间就去找了找ajax的教程看了看,但是没怎么看懂,一大堆什么XMLHttpRequest 什么的,试了试还是各种理不清,找官方demo改了改,发现mui的ajax还是挺好懂的,格式也比较固定,对于菜鸟的我来说感觉这个才是最好的,不要先来一大堆没用的,废话少说,试试看就知道咯。

第二步:ajax跨域请求的简单实例

先来个最简单的直接点击按钮弹出返回的数据,只要这个成功了,那么改改还是很容易的。
【html部分】:

 <button type="button" id="confirm" class="mui-btn mui-btn-royal mui-btn-block">发送请求</button>

【js部分】:

<script src="js/mui.min.js"></script>  
<script>  
    //发送请求按钮的点击事件  
    document.getElementById("confirm").addEventListener('tap', function() {  
        var url = "http://fanyi.youdao.com/openapi.do?keyfrom=abc1243&key=1207861310&type=data&doctype=json&version=1.1&q=good";  
        mui.ajax(url,{  
            dataType:'json',//服务器返回json格式数据  
            type:'GET',//HTTP请求类型  
            timeout:10000,//超时时间设置为10秒;  
            success:function(data){  
                //JSON.stringify()将 JSON对象转为json字符串   
                var data = JSON.stringify(data);  
                alert(data);  
            },  
            error:function(xhr,type,errorThrown){  
                //异常处理;  
                console.log(type);  
            }  
        });  
    });  
</script>

第三步:传递参数的ajax跨域请求

上面URL中把各种请求参数写固定了,不便于我们后期做修改,现在用ajax的data属性。
首先我们增加一个搜索输入框用于输入要翻译的内容:
修改html的代码如下:(样式文件没有引入,样式也没有写出来,主要是为了写清楚思路)
【html部分】

<form name="search" method="get">  
        <div class="mui-input-row mui-search input-search">  
        <input type="search" id="search"  class="mui-input-speech mui-input-clear" placeholder="请输入内容...">  
        </div>  
        <button type="button" id="confirm" class="mui-btn mui-btn-royal mui-btn-block">发送请求</button>  
</form> 

【js部分】(修改部分的代码)

var search = document.getElementById("search");  
//发送请求按钮的点击事件  
document.getElementById("confirm").addEventListener('tap', function() {  
    var url = "http://fanyi.youdao.com/openapi.do";  
    mui.ajax(url,{  
        data:{  
            keyfrom:"abc1243",  
            key:"1207861310",  
            type:"data",  
            doctype:"json",  
            version:"1.1",  
            q:search.value  
        },  
        dataType:'json',//服务器返回json格式数据  
        type:'post',//HTTP请求类型  
        timeout:10000,//超时时间设置为10秒;  
        success:function(data){  
            //JSON.stringify()将 JSON对象转为json字符串   
            var data = JSON.stringify(data);  
            alert(data);  
        },  
        error:function(xhr,type,errorThrown){  
            //异常处理;  
            console.log(type);  
        }  
    });  
});

第四步:ajax跨域请求怎么处理获取的数据

我们刚刚只是把数据alert出来了但是并没有进行任何后期操作,比如把有用信息获取写出来。
我们是把刚刚那个变成了json字符串alert出来的,也就是说是字符串而不是对象,获取键值对必须是对对象进行操作。
那么我们首先使用eval函数把json字符串转化成JavaScript对象:

//将json字符串转化成JavaScript对象  
var obj = eval ("(" + response + ")");

然后我们就可以对obj对象进行操作了,json键值对的[] 中括号的使用如下:
JSON就是一串字符串 只不过元素会使用特定的符号标注。

  • {} 双括号表示对象
  • [] 中括号表示数组
  • "" 双引号内是属性或值
  • : 冒号表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)
    所以 {"name": "Michael"} 可以理解为是一个包含name为Michael的对象,而[{"name": "Michael"},{"name": "Jerry"}]就表示包含两个对象的数组。
    var LangShen = {"Name":"Langshen","AGE":"28"};
      这是一个json对象;{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数上面声明了一个名为“LangShen”的对象,多个属性或函数用,(逗号)隔开,因为是对象的属性,
      那么我们访问的时候会有两种方式:
    访问方式一:LangShen.Name、LangShen.AGE
      访问方式二:LangShen["Name"]、LangShen["AGE"]
      就是这么一个小小的方式,会有什么区别呢?
      在实际应用中,第一种方式的.Name实际是作为一个对象被调用,而LangShen["Name"]里的name却可以是一个字符串。
    有道翻译API获取实例:

我只是写出了基本思路,无非就是把对于内容写在对应的位置。

document.getElementById("translation").innerHTML=obj.translation;   
document.getElementById("us-phonetic").innerHTML=obj.basic["us-phonetic"];  
document.getElementById("phonetic").innerHTML=obj.basic["phonetic"];  
document.getElementById("uk-phonetic").innerHTML=obj.basic["uk-phonetic"];  
document.getElementById("explains").innerHTML=obj.basic["explains"];  
document.getElementById("query").innerHTML=obj.query;  
//遍历读取键值对写入  
for(var str in obj.web){  
     var keyid=document.getElementsByName("webkey")[str].id;  
     var Valueid=document.getElementsByName("webvalue")[str].id;  
     document.getElementById(keyid).innerHTML=obj.web[str]["key"];  
     document.getElementById(Valueid).innerHTML=obj.web[str]["value"];  
}   

如果需要在普通页面使用,可以使用jsonp:

<!doctype html>  
<html>  

    <head>  
        <meta charset="UTF-8">  
        <title></title>  
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
        <link href="css/mui.min.css" rel="stylesheet" />  
    </head>  
    <body>  
        <header class="mui-bar mui-bar-nav">  
            <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>  
            <h1 class="mui-title">native-JavaScript</h1>  
        </header>  
        <div class="mui-content mui-content-padded">  
            <div class="mui-input-row">  
                <label>输入关键词:</label>  
                <input id="input" type="text" placeholder="普通输入框">  
            </div>  
            <button id="btn" type="button" class="mui-btn mui-btn-blue mui-btn-block">翻译</button>  
            <div id="output"></div>  
        </div>  

        <script type="text/javascript">  
            var inputEl = document.querySelector("#input");  
            document.querySelector('#btn').addEventListener('click',function () {  
                var url = "http://fanyi.youdao.com/openapi.do";  
                var data = {  
                    "keyfrom": "abc1243",  
                    "key": "1207861310",  
                    "type": "data",  
                    "doctype": "jsonp",  
                    "version": "1.1",  
                    "q": inputEl.value,  
                    "callback": "jsonpcallback"  
                }  

                var buffer = [];  
                for (var key in data) {  
                    buffer.push(key + '=' + encodeURIComponent(data[key]));  
                }  
                var fullpath = url + '?' + buffer.join('&');  
                CreateScript(fullpath);     
            })  

            function CreateScript(src){  
                var el = document.createElement('script');  
                el.src = src;  
                el.async = true;  
                el.defer = true;  
                document.body.appendChild(el);  
            }  

            function jsonpcallback(rs) {  
                console.log(JSON.stringify(rs));  
                document.getElementById("output").innerHTML = JSON.stringify(rs);  
            }  
        </script>  
    </body>  

</html>
收起阅读 »

有个DCloud的项目,求外包

外包

公司在北京,北京的同学优先哈,QQ:130775

公司在北京,北京的同学优先哈,QQ:130775

iOS离线打包-支付插件配置

离线打包

目前支付插件支持支付宝、微信支付和苹果内购支付:

支付插件首先需要到各开放平台申请帐号,申请查看该文档

配置使用的支付模块

参考该文档配置支付插件使用的库

支付宝

依赖库 系统库 资源文件
liblibPayment.a,libalixpayment.a,AlipaySDK.framework Security.framework,CoreMotion.framework,SystemConfiguration.framework,CFNetwork.framework,libc++.dylib AlipaySDK.bundle

微信支付

依赖库 系统库 资源文件
liblibPayment.a, libwxpay.a, libWeChatSDK_pay.a libsqlite3.0.dylib, libz.dylib, CoreTelephony.framework, SystemConfiguration.framework

配置支付平台参数

feature.plist 配置

在工程中搜索 feature.plist 文件(位于PandoraApi.bundle中),在 Payment-> extend 节点下添加对应平台的配置

支付宝

在URL Types 中添加配置: identifier 填写 alixpay ,URL Schemes 填写 alix[后面是您在支付宝平台申请的appid] ,如果没有该项按照图中的格式创建


注意:
iOS9.0以上版本需要在info.plist增加以下配置

微信支付

在URL Types 中添加配置: identifier 填写 weixin ,URL Schemes 填写wx[后面是您在微信平台申请的appkey] ,如果没有该项按照图中的格式创建


注意:
<a id="ulink"/>
HBuilderX2.3.4+ 版本需要配置 Universal Link
在info.plist root 节点添加UniversalLinks项,值和微信开放平台配置的一致,参考如下:

查看工程里的AppDelegate.m文件里是否有下面的方法:
>//@Summary:通用链接
-(BOOL)application:(UIApplication )application continueUserActivity:(NSUserActivity )userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler {
[PDRCore handleSysEvent:PDRCoreSysEventContinueUserActivity withObject:userActivity];
restorationHandler(nil);
return YES;
}

注意:
iOS9.0以上版本需要在info.plist增加以下配置

继续阅读 »

目前支付插件支持支付宝、微信支付和苹果内购支付:

支付插件首先需要到各开放平台申请帐号,申请查看该文档

配置使用的支付模块

参考该文档配置支付插件使用的库

支付宝

依赖库 系统库 资源文件
liblibPayment.a,libalixpayment.a,AlipaySDK.framework Security.framework,CoreMotion.framework,SystemConfiguration.framework,CFNetwork.framework,libc++.dylib AlipaySDK.bundle

微信支付

依赖库 系统库 资源文件
liblibPayment.a, libwxpay.a, libWeChatSDK_pay.a libsqlite3.0.dylib, libz.dylib, CoreTelephony.framework, SystemConfiguration.framework

配置支付平台参数

feature.plist 配置

在工程中搜索 feature.plist 文件(位于PandoraApi.bundle中),在 Payment-> extend 节点下添加对应平台的配置

支付宝

在URL Types 中添加配置: identifier 填写 alixpay ,URL Schemes 填写 alix[后面是您在支付宝平台申请的appid] ,如果没有该项按照图中的格式创建


注意:
iOS9.0以上版本需要在info.plist增加以下配置

微信支付

在URL Types 中添加配置: identifier 填写 weixin ,URL Schemes 填写wx[后面是您在微信平台申请的appkey] ,如果没有该项按照图中的格式创建


注意:
<a id="ulink"/>
HBuilderX2.3.4+ 版本需要配置 Universal Link
在info.plist root 节点添加UniversalLinks项,值和微信开放平台配置的一致,参考如下:

查看工程里的AppDelegate.m文件里是否有下面的方法:
>//@Summary:通用链接
-(BOOL)application:(UIApplication )application continueUserActivity:(NSUserActivity )userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler {
[PDRCore handleSysEvent:PDRCoreSysEventContinueUserActivity withObject:userActivity];
restorationHandler(nil);
return YES;
}

注意:
iOS9.0以上版本需要在info.plist增加以下配置

收起阅读 »