文档章节

使用HBuilder基于HTML5编写新闻客户端APP的一些实验

lxrmido
 lxrmido
发布于 2014/05/10 14:54
字数 4891
阅读 3345
收藏 9
点赞 1
评论 10

一、一些基本概念

1、HBuilder

按照我的理解,HBuilder是一个基于eclipse二次开发的IDE,主要对HTML5的开发做了许多优化,刚发布没多久,目前基本稳定,但是仍然有一些BUG。

用HBuilder开发移动APP的好处是可以连接手机实时调试APP(对于Android其实也就是用adb跟DDMS),连接手机后IDE的界面上会出现你所连接的手机,对项目中的文件修改回实时同步到手机上,下图是ADT和HB的对比:

2、HTML5 Plus

其实就是HBuildeBuild发团队推出的一种框架,尽管官方说这是一个开放性的HTML5的扩展标准,但是从目前其提供的资源以及行为来看,我跟人不太认同官方的说法。目前也只有HBuilder能打包基于HTML5+的项目,同样地,HBuilder开发移动应用用的就是这个框架。

目前市场上可见的、基于此框架做的应用有CSDN的新闻客户端,基于此框架可以调用许多手机的原生服务。以下分别是CSDN的客户端及HBuilder提供的示例程序,HBuilder中有这两个项目的源代码:

二、实验目标(需求分析)

1、目标

首先,是确定一下用HB和H5+能不能做出原生手机应用的效果,其次是看看开发的复杂度。

在此,我定下一个目标:仿照网易新闻的APP,用HB做一个新闻客户端的雏形,重点是做出几个手机客户端常见的手势操作以及一些动画效果。

2、分析

下图是对网易新闻客户端使用过程的几个截图,也是这次要实现的内容:

①、首页(主页面),包含一个LOGO、一个菜单按钮、一个用户按钮、一个导航栏、一个新闻标题列,标题列的顶部是一个图片轮播栏;

②、在首页中拖动页面,页面可渐渐缩放以呈现出菜单,点击菜单按钮也是同样的效果;

③、在首页左右拖动可在头条、推荐、娱乐等导航间进行切换;

④、点击新闻列表进入新闻内容页,在内容页中拖动页面可返回。

第一步就是实现上面的内容,其中大部分手势操作在许多原生应用中都是司空见惯的,但是对于H5应用来说还是比较罕见,也没有几个案例可以参考,因此就蛮力开撸了。


三、正文

1、大概思路

既然是基于HTML5的,那么就必须发挥HTML5的优势。其一就是兼容性,一次开发即可在多个平台上使用,这就意味着同样需要在代码中进行设备检测,也要进行屏幕自适应,这些都是移动端网站用得比较多的手段了,也不再详述。官方也说了建议别用各种JS库,那么所有动画效果、页面布局都需要自己来写。

当然,必要的偷懒还是得有的,用个jQuery,在不影响性能的地方使用也无妨。

按照上面的分析,目前要做的是两个页面:第一个页面就是新闻列表页,包含那个缩放菜单;第二个页面是新闻内容的查看页面。

看完HTML5+的文档(虽然内容不多,但是该有的内容都有,还是不错的),大概明白了新闻列表页中的所有效果都得基于HTML5来写,也就是说,写这个页面可以用PC浏览器来进行调试。

进入新闻内容页的时候,可以用H5+提供的窗体接口,此页面中拖动返回之类的操作可以利用修改窗体的位置来实现。

页面中的图标都可以在FontAwesome这个图标字体里边找到,可以省下一大笔时间。

那么,接下来就是开撸了。

2、代码结构

代码列表如下:

index是新闻列表页,view是新闻内容查看页,pic是图片浏览页(点击图片会进到这个页面,先放置);js目录中,frame.js中放置一些公用代码,main.js是处理index逻辑的代码,main.XXX的几个js文件则是头条、推荐等导航的逻辑分管。

3、DOM操作及模板机制

从图片轮播到新闻列表,都可以先做好一个模板然后给予模板动态生成,所以,首先,我写了几个模板:

<section data-node="tpl" style="display:none;">
    <div class="content-imghead" data-node="imghead">
        <div class="content-imghead-container" data-node="container">
        </div>
    </div> 
    <div class="content-imgtitle" data-node="imgtitle">
        <div class="content-imgtitle-desc" data-node="desc"></div> 
        <div class="content-imgtitle-words" data-node="words"></div>
        <div class="conntent-imgtitle-dot i1" data-node="i1"></div>
        <div class="conntent-imgtitle-dot i2" data-node="i2"></div> 
        <div class="conntent-imgtitle-dot i3" data-node="i3"></div>
        <div class="conntent-imgtitle-dot i4" data-node="i4"></div>
    </div>
    <div class="content-horitem" data-node="horitem"> 
        <img class="content-horitem-img" src="img/news_default_320_160.png" data-node="img"></img>
        <div class="content-horitem-title" data-node="title">新闻标题新闻标题新闻标题新闻标题新闻标题</div> 
        <div class="content-horitem-desc" data-node="desc">副标题描述副标题描述副标题描述副标题描述</div>
        <div class="content-horitem-icon" data-node="icon"><i class="icon-facetime-video"></i></div>
    </div>
</section>

上面的代码中,从上而下分别是图片轮播的轮播页、图片轮播的标题页、新闻标题列表项的模板。HTML代码中有data-node这个属性,这是后面用来获取DOM用的,data-node的相关JS代码如下:

var F = window['F'] = {
    getNodes : function(obj){
        var i;
        if(!obj.childNodes || obj.childNodes.length == 0){
            return obj;
        }
        for(i = 0; i < obj.childNodes.length; i ++){
            if(obj.childNodes[i].dataset && obj.childNodes[i].dataset.node){
                obj[obj.childNodes[i].dataset.node] = F.getNodes(obj.childNodes[i]);
            }
        }
        return obj;
    }
};

也就是一个简易的DOM获取的方式,通过这句代码:

_doc = F.getNodes($('body')[0]);

可以分层遍历获取body下所有带了data-node的节点,譬如上面的模板,可以通过_doc.tpl.imghead来取得图片轮播的模板。

4、页面

调界面的过程是痛苦的,持续三四个小时的眼镜干涩的调整过程不提,总而言之最终写好的页面长这样:

仿真度也足够了吧?在此感谢FontAwesome,不然画图标可能还要花上一两个小时……

(其实做完界面之后我就下班了,那天是4.29,就快五一了,心情激动啊)

最终首页的布局如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>...</title>
    <link rel="stylesheet" type="text/css" href="css/main.css"/>
    <link rel="stylesheet" type="text/css" href="css/font-awesome.css"/>
    <script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/frame.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/main.top.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/main.recommend.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/main.entertainment.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/main.sport.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/main.finance.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/main.js" type="text/javascript" charset="utf-8"></script>
    <style type="text/css"></style>
</head>
<body>
	<div class="side" data-node="side_left">
		<div class="side-list" data-node="list">
			<div class="side-list-item selected"><i class="icon-list-alt"></i>新闻</div> 
			<div class="side-list-item"><i class="icon-rss"></i>订阅</div>
			<div class="side-list-item"><i class="icon-picture"></i>图片</div>
			<div class="side-list-item"><i class="icon-film"></i>视频</div>
			<div class="side-list-item"><i class="icon-comments-alt"></i>跟帖</div>
			<div class="side-list-item"><i class="icon-headphones"></i>电台</div>
		</div> 
	</div>
	<div class="page" data-node="page_main"> 
		<div class="touchcover" data-node="cover"></div>
		<div class="header" data-node="header"> 
			<div class="header-btn-left" data-node="btn_left_menu"><i class="icon-reorder"></i></div>
			<div class="header-btn-right"><i class="icon-user"></i></div>
		</div>
		<div class="navbar" data-node="navbar">
			<div class="navi selected" data-node="navi0">头条</div> 
			<div class="navi" data-node="navi1">推荐</div>
			<div class="navi" data-node="navi2">娱乐</div> 
			<div class="navi" data-node="navi3">体育</div>
			<div class="navi" data-node="navi4">财经</div>
			<div class="naviselector" data-node="selector"></div> 
		</div>
		<div class="naviswitch"><i class="icon-angle-down"></i></div> 
		<div class="container" data-node="container">
			<div class="content" data-node="content1"> 

			</div>
			<div class="content" data-node="content2">
 
			</div>
			<div class="content" data-node="content3">

			</div>
			<div class="content" data-node="content4">

			</div>
			<div class="content" data-node="content5">

			</div> 
		</div>
	</div> 
	<section data-node="tpl" style="display:none;">
		<div class="content-imghead" data-node="imghead">
			<div class="content-imghead-container" data-node="container">
			</div>
		</div> 
		<div class="content-imgtitle" data-node="imgtitle">
			<div class="content-imgtitle-desc" data-node="desc"></div> 
			<div class="content-imgtitle-words" data-node="words"></div>
			<div class="conntent-imgtitle-dot i1" data-node="i1"></div>
			<div class="conntent-imgtitle-dot i2" data-node="i2"></div> 
			<div class="conntent-imgtitle-dot i3" data-node="i3"></div>
			<div class="conntent-imgtitle-dot i4" data-node="i4"></div>
		</div>
		<div class="content-horitem" data-node="horitem"> 
			<img class="content-horitem-img" src="img/news_default_320_160.png" data-node="img"></img>
			<div class="content-horitem-title" data-node="title">新闻标题新闻标题新闻标题新闻标题新闻标题</div> 
			<div class="content-horitem-desc" data-node="desc">副标题描述副标题描述副标题描述副标题描述</div>
			<div class="content-horitem-icon" data-node="icon"><i class="icon-facetime-video"></i></div>
		</div>
	</section>
</body>
</html>

新闻内容页的布局如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
		<title></title>
		<link rel="stylesheet" type="text/css" href="css/view.css"/>
		<link rel="stylesheet" type="text/css" href="css/font-awesome.css"/>
		<script src="js/frame.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
		<script src="js/view.js" type="text/javascript" charset="utf-8"></script>
		<style type="text/css"></style>
	</head> 
	<body>
		<div class="page" data-node="page_view">
			<div class="header" data-node="header">
				<div class="header-btn-left" data-node="btn_back">
					<i class="icon-angle-left"></i>
				</div> 
				<div class="header-tip" data-node="tip">1245</div>
			</div>
			<div class="content" data-node="content">
				<h3 class="title">新闻标题</h3>
				<p class="note">副标题&nbsp;02-02 00:00</p>
				      
				<p>新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容</p>
				<p>新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容</p>
				<p>新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容</p>
				<p>新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容</p>
				<p>新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容</p>
				<p>新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容</p>
				<p>新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容</p>
				<p>新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容新闻内容</p>
			</div> 
			<div class="footer" data-node="footer">
				<input type="text" class="footer-reply" placeholder="写跟帖" data-node="input" /> 
				<div class="footer-btn-favor" data-node="btn_favor"><i class="icon-star-empty"></i></div>
				<div class="footer-btn-share" data-node="btn_share"><i class="icon-share"></i></div>
			</div>
		</div>
	</body>
</html>

5、屏幕自适应

做这个的时候,手头上的测试机有:iPhone 5、Note 3、MI 3、MI 2S

其实移动端的页面自适应,最关键的还是devicePixelRatio这个值,看iPhone4的分辨率比3GS高了四倍,其实对于网页来说还是一样的分辨率,看Note 3的1080P多高,其实在页面上比起肾果来也多不了多少……

因此,我可耻地用了最省事的自适应方法:在页面加载完后一次insertRule来修改样式!

这样做的好处是省事省资源(生下来的资源可以做很多事啊……),坏处是面对屏幕翻转、页面尺寸更改等事件会表现得一塌糊涂。

首先,我用了这么一坨代码来获取页面的尺寸属性以及设定一些属性

G = {};
// 屏幕宽度
G.WIDTH                = $(window).width(),
// 屏幕高度
G.HEIGHT               = $(window).height(),
// 首页滑到这个位置则判定用户要打开左侧菜单
G.LIMIT_SLIDE_PAGESIDE = G.WIDTH / 4;
// 菜单打开时,首页滑到这个位置则认为用户要关闭菜单
G.LIMIT_SLIDE_PAGEBACK = G.WIDTH / 4 * 3;
// 菜单打开时首页页面滑到这个位置
G.SITE_X_PAGESIDE      = G.WIDTH / 3 * 2;
// 页面缩放最小值
G.SCALE_MAX_PAGESIDE   = 0.2;
// 菜单打开时页面缩放的比率
G.SCALE_PAGESIDE       = 1 - G.SITE_X_PAGESIDE / G.WIDTH * G.SCALE_MAX_PAGESIDE;
// 菜单滑动的动画时间
G.TIME_SLIDE_ANIMATE   = 200;
// 页面导航切换的动画时间
G.TIME_SPAGE_ANIMATE   = 200;
// 菜单打开时,菜单的顶部对齐缩小后的页面顶部
G.SITE_SCALE_BOTTOM    = (G.HEIGHT - G.SCALE_PAGESIDE * G.HEIGHT) / 2;

然后,我又用了这么个方式来让一些页面元素自适应:

style = document.styleSheets[document.styleSheets.length - 1];
style.insertRule('.container{height:' + (G.HEIGHT - 80) + 'px;}', 0);
style.insertRule('.content{height:'   + (G.HEIGHT - 80) + 'px; width:' + G.WIDTH + 'px;}', 0);
style.insertRule('.content-imghead{height:'   + (G.WIDTH / 2 - 1) + 'px; width:' + G.WIDTH + 'px;}', 0);
style.insertRule('.content-imghead-img{height:'   + (G.WIDTH / 2 - 1) + 'px; width:' + G.WIDTH + 'px;}', 0);
style.insertRule('.content-imghead-container{height:'   + (G.WIDTH / 2 - 1) + 'px;}', 0);
style.insertRule('.content-horitem{width:'   + (G.WIDTH - 24) + 'px;}', 0);

CSS的代码很枯燥,在此就不提了。

6、手势动画

这其实是APP最重要的部分,手势的合理与否很大程度上决定了应用的生死(这是一个伏笔)。

左右滑动可以通过设置style.left的值、可以用translateX来实现,缩放效果则只能用transform的scale函数来实现(这也是一个伏笔)。

我定义了一堆变量用来存放动画过程的一些参数:

// 运行时参数
R = {};
R.isIOS = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/iPad/i);
R.PAGE_S    = 'main',
R.container = _doc.page_main.container;
R.navIndex  = 0;
R.navCount  = 5;
R.animating = false;
R.scaleRate = 1;
// 页面从哪里开始滑
R.fromX     = 0;
// 页面滑动的步进
R.step_t    = 64;
// 页面缩放的步进
R.step_s    = (1 - G.SCALE_PAGESIDE) / G.SITE_X_PAGESIDE * 64;

其中,isIOS这个是直接抄CSDN的APP的,在写完这个之后我还做了对chrome、ASOP自带浏览器等的判断,最终还是删掉了。

在滑动页面开关菜单的过程中,最重要的是保证动作的合理与流畅,譬如用户滑动到一定程度后松手时,页面是回弹(操作取消)还是自动滑到另一边(操作生效)、自动滑动的过程中滑动速率跟用户手动滑动的部分速率一致、动画效果不卡帧等。

因此,我在新闻列表页中定义了五套touch事件处理函数来分别处理不同的操作,分别是:

①、没有任何操作时(路由)

②、动作可能是滑到左侧列表菜单

③、左侧菜单打开时的响应

④、可能是左侧菜单滑回页面

⑤、可能是 主页横向左侧翻页

⑥、 主页横向右侧翻页

判定逻辑如下:

T.on(_doc, 'start', function(e){
    var sx, sy, cx, cy, rt, fx, ft, step_t, step_s, an = false;
    switch(e.touches.length){
    // 触摸事件
    // 单点手势
    case 1:
        sx = e.touches[0].clientX;
        sy = e.touches[0].clientY;
        switch(R.PAGE_S){
        // 在主屏幕中,判断是否切换到菜单
        case 'main':
            T.on(_doc.page_main, 'move'  , m0);
            T.on(_doc.page_main, 'end'   , e0);
            T.on(_doc.page_main, 'calcel', c0);                 
            break;
        // 在左侧菜单中,判断是否切换回主屏幕
        case 'side-l':
            T.on(_doc.page_main.cover, 'move'  , m2);
            T.on(_doc.page_main.cover, 'end'   , e2);
            T.on(_doc.page_main.cover, 'calcel', c2);   
            break;
        }
        break;
    default:
        break;
    }
    /* ... */
}

(因为是第一次用H5做APP,对其不熟悉,也许其中有不少多余的部分)

T.on是另外封装的一个兼容函数,相关代码如下:

var T = window['T'] = {
    on : function(dom, type, func){
        if(("ontouch" + type) in dom){
            dom["ontouch" + type] = func;
        }else{
            dom.addEventListener("touch" + type, func);
        }
    },
    off : function(dom, type, func){
        if(("ontouch" + type) in dom){
            dom["ontouch" + type] = null;
        }else{
            dom.removeEventListener("touch" + type, func);
        }
    },
    offNormal : function(dom, func1, func2, func3){
        if('ontouchstart' in dom){
            dom.ontouchmove   = null;
            dom.ontouchcancel = null;
            dom.ontouchend    = null;
        }else{
            dom.removeEventListener('touchmove',   func1);
            dom.removeEventListener('touchend',    func2);
            dom.removeEventListener('touchcancel', func3);
        }
    }
};

图片轮播则用了另外的一套touch事件,绑定在imghead上。

说起拖动的原理,在我的理解中,关键就是两个坐标:开始拖动时的横坐标SX、当前拖动位置的横坐标CX,拖动距离就是CX - SX,那么只需要把页面的位移设置为CX - SX就完事了。

当触摸事件结束之后,该如何自动完成剩下的动画?最初,我是直接用了CSS3的transition属性,当触摸结束后,给元素加一个transition:linear;之类的样式,动画效果结束后再去掉这个样式,后来,我发现这个样式在android平台下存在一个略微严重的问题:卡。

也不知道ASOP自带的浏览器是怎么回事,也不知道为什么HBuilder在打包的时候要封装Android的自带浏览器,这个浏览器的性能真的很糟糕,无论多好的手机,只要用这个浏览器,其表现跟若干年前的单核手机没什么区别。

其实说到这,这篇文章已经可以结束了,事实上,做到这,我已经没有什么激情再把这个应用原型写下去了,因为我预感目前在Android上H5+是玩不下去了。

最后我用了这么一个方式来兼顾动画效果:

function menuSlideIn(){
    if(R.animating){
        return;
    }
    R.PAGE_S =  'side-l';
    if(R.isIOS){
        _menuSlideIn();
    }else{
        $(_doc.page_main.cover).show();
        _doc.page_main.style.left = G.SITE_X_PAGESIDE + 'px';
    }
}
function _menuSlideIn(){
    R.animating                          =  true;
    R.scaleRate                          -= R.step_s;
    R.fromX                              += R.step_t;
    _doc.page_main.style.left            =  R.fromX + 'px';
    _doc.page_main.style.webkitTransform =  'scale(' + R.scaleRate + ', ' + R.scaleRate + ')';
    if(R.fromX >= G.SITE_X_PAGESIDE){
        $(_doc.page_main.cover).show();
        R.animating                          = false;
        _doc.page_main.style.left            = G.SITE_X_PAGESIDE + 'px';
        _doc.page_main.style.webkitTransform = 'scale(' + G.SCALE_PAGESIDE + ', ' + G.SCALE_PAGESIDE + ')';
    }else{
        requestAnimationFrame(_menuSlideIn);
    }
}

对于左侧的菜单,在非IOS上禁用缩放效果。甚至在用户拖动完毕后不显示动画效果而直接让菜单闪到那个位置,卡帧的动画还不如不播,因此我干脆用了requestAnimationFrame这个Android上没有的函数。

最后是新闻内容页,用户点击新闻时,调用这么个方法打开新页面:

plus.ui.createWindow("view.html").show('slide-in-right', 200);

万幸,H5+自带了一系列的窗口打开、关闭动画效果。

因为这个页面是在新窗口的,因此要实现拖动返回的话,就不再是设置DOM的style.left属性了,而是调用这么个方法:

W.setOption({left : ox});

来设置窗体的位置。

相应地,设置窗体位置就要换一种算法了,因为窗体移动后,每次检测到的X位置所相对的位置都改变了。

假设页面一开始的偏移是OX = 0,用户触摸屏幕的位置是SX,用户第一次移动时的位置是CX,那么,把OX设置为CX - SX,然后把页面的位置设置为OX;

第二次以及之后的移动事件中,OX = OX + CX - SX,然后把页面的偏移设置为OX;

结束触摸之后,假如当前页面的偏移达到了返回的判定点,那么调用:

plus.ui.closeWindow(W, 'slide-out-right', 200);

关掉这个窗口,否则让页面动画返回左边缘。

在IOS上,以上的动画效果很流畅完美地实现了,但是,不知道是不是我的使用方式不对,在Android下这段代码的表现是悲剧的。

在拖动过程中,页面不断地闪动,拖着拖着,页面就消失了!

所以,这段代码,我是这么写的:

function m1(e){
    cx = e.touches[0].clientX;
    cy = e.touches[0].clientY;
    _doc.page_view.header.tip.innerHTML = cx;
    if(R.isIOS){
        if(lx !== null){
            ox = ox + cx - sx;
            W.setOption({
                left : ox
            });
        }else{
            ox = cx - sx;
            W.setOption({
                left : ox
            });
        }
    }
}

是的,对于非IOS的系统,我直接取消掉了这个效果。

至此,文章真的要结束了,因为在Android上,这个应用雏形的用户体验已经低到了极致。


四、总结

实验结果是:H5+可以做APP,不太能做APK。

我衷心希望这篇文章里出现的Android下的糟糕表现是我的技术及实现思路太糟糕而造成的,因为我真心渴望可以直接用HTML5写出媲美原生的应用的那一天的到来。

也许代码中还有很多的可以优化的地方,也许进行极致的优化之后应用可以运行得比较流畅,但这却是不是我所想看到的,需要做得这么完美才能实用的技术,是无法推广的。

对这个半成品都算不上的应用感兴趣的话,可以移步http://www.lxrmido.com/webcv2/看看实际效果

对代码感兴趣的同学可以把svn://www.lxrmido.com/webcv2这个目录checkout下来看看,希望对你有所帮助

最后的最后,希望大家可以告诉我是不是真的哪里想歪了,总感觉HBuilder不应该那么脆弱……


© 著作权归作者所有

共有 人打赏支持
lxrmido
粉丝 5
博文 3
码字总数 11150
作品 0
广州
程序员
加载中

评论(10)

lxrmido
lxrmido

引用来自“snwei”的评论

链接失效了。能不能发一份到2240934991@qq.com,谢谢
年代久远,已经找不到了,文中的内容也过时了,现在可以直接用HCloud的MUI去实现了
s
snwei
链接失效了。能不能发一份到2240934991@qq.com,谢谢
王超男
王超男
链接失效了, 可以发份代码(新闻类都可以)到邮箱547196502@qq.com 吗?谢谢了,现在刚刚接触这方面东西,有点理解不太好
苏荷酒吧
问个问题
1、Hbuilder怎么连接后台服务器开发
2、Hbuilder怎么实现跨域问题,或者打包
yong230
yong230
写的很好,最近我也在学习H5 app开发,checkout 不了 能发份到yong458@126.com吗,谢谢
EditPlus
EditPlus
好文章。
郑柯
郑柯
我也希望这玩意好用,同事推荐用这个来开发安卓程序,我正在考察
mmogm
mmogm
checkout 不了 能发份到 dore2046@126.com 谢谢
lxrmido
lxrmido

引用来自“10yuecf”的评论

svn登录需要密码?
读取是不需要的
1
10yuecf
svn登录需要密码?
用vue快速开发app的脚手架工具

前言 多页面应用于结构较于简单的页面,因为简答的页面使用router又过于麻烦.本脚手架出于这样的场景被开发出来. 使用脚手架搭配Hbuilder也同样可以快速使用vue开发安卓和IOS APP. 本文最大特...

滕亚庆_ArH ⋅ 06/08 ⋅ 0

VR虚拟现实网页+H5Builder实现手机VR效果(可生成apk,ios)

A-Frame框架可实现VR的各种效果,这是它的链接:https://aframe.io/ 可通过它的doc文档查看它的相关编码规范 : https://aframe.io/docs/0.8.0/introduction/ 我通过HBuilder 编辑器 + A-Fr...

HaleyLiu ⋅ 05/28 ⋅ 0

因为违法使用开源资源,他们不仅要道歉还要赔钱

近日, 北京市集佳律师事务所代理原告数字天堂(北京)网络技术有限公司,在诉被告柚子(北京)科技有限公司、柚子(北京)移动技术有限公司侵犯计算机软件著作权纠纷案件中获得胜诉:北京知识...

周其 ⋅ 04/29 ⋅ 0

利用HBuilder打包前端开发webapp为apk

现在的前端开发可谓是百花齐放,什么都可以做,今天就简单的介绍h5页面如何打包为apk,在移动设备上运行 安装node 如果是做前端的er,这个应该就不用过多介绍了 常规开发 比如希望实现的功能等 ...

webmirror ⋅ 05/02 ⋅ 0

个推ios系统receive监听事件无限循环

hbuilder开发,个推,ios系统receive监听事件无限循环,求助!!!急求!!!!

其他昵称120 ⋅ 06/21 ⋅ 0

svn检出时报错,Error: Repository moved temporarily to 'xxx'

用HBuilder自带的svn插件检出没有任何问题,用webstorm的SVNTool检出和用小乌龟svn检出就会报这个错误 求大神解惑

程序员与程序猿 ⋅ 04/28 ⋅ 0

【CSS实践】——如何将一个div打造成一条仿颜色渐变线

前言 我们公司最近在设计首页的时候美工标题下方有一条颜色渐变的线,我尝试了很多种方法但都没有达到预想的效果,最终通过了div设计出来了! 内容 其实设计的效果就是像hbuilder中文字下方区...

changyinling520 ⋅ 04/26 ⋅ 0

Eclipse的JQuery提示插件-Spket(别试了,没什么效果,且安装设置麻烦)

参考: http://www.cnblogs.com/shulin/archive/2010/08/09/1796146.html 我测试了,但是没用起来,原因有如下几点: 1、配置复杂,且提示效果不佳。 2、现在市面上前端框架非常的多,而这个...

easonjim ⋅ 2017/10/26 ⋅ 0

Hbuilder打包IOS关于定位描述问题

由于某些问题,上传的IPA包被苹果拒绝了,修改之后重新打包上传,一直传不上去,原因如下: 苹果对于隐私这块比较重视,使用了用户的位置信息需要给出明确的提示告诉用户,之前的文章中也有介...

尹吉欢 ⋅ 04/26 ⋅ 0

ajax实现简单的点击左侧菜单,右侧加载不同网页

实现:ajax实现点击左侧菜单,右侧加载不同网页(在整个页面无刷新的情况下实现右侧局部刷新,用到ajax注意需要在服务器环境下运行,从HBuilder自带的服务器中打开浏览效果即可) 原理:aja...

祈澈姑娘 ⋅ 05/03 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

个人博客的运营模式能否学习TMALL天猫质量为上?

心情随笔|个人博客的运营模式能否学习TMALL天猫质量为上? 中国的互联网已经发展了很多年了,记得在十年前,个人博客十分流行,大量的人都在写博客,而且质量还不错,很多高质量的文章都是在...

原创小博客 ⋅ 今天 ⋅ 0

JavaScript零基础入门——(十一)JavaScript的DOM操作

JavaScript零基础入门——(十一)JavaScript的DOM操作 大家好,欢迎回到我们的JavaScript零基础入门。最近有些同学问我说,我讲的的比书上的精简不少。其实呢,我主要讲的是我在开发中经常会...

JandenMa ⋅ 今天 ⋅ 0

volatile和synchronized的区别

volatile和synchronized的区别 在讲这个之前需要先了解下JMM(Java memory Model :java内存模型):并发过程中如何处理可见性、原子性、有序性的问题--建立JMM模型 详情请看:https://baike.b...

MarinJ_Shao ⋅ 今天 ⋅ 0

深入分析Kubernetes Critical Pod(一)

Author: xidianwangtao@gmail.com 摘要:大家在部署Kubernetes集群AddOn组件的时候,经常会看到Annotation scheduler.alpha.kubernetes.io/critical-pod"="",以表示这是一个关键服务,那你知...

WaltonWang ⋅ 今天 ⋅ 0

原子性 - synchronized关键词

原子性概念 原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。 原子性的实现方式 在jdk中,原子性的实现方式主要分为: synchronized:关键词,它依赖于JVM,保证了同...

dotleo ⋅ 今天 ⋅ 0

【2018.06.22学习笔记】【linux高级知识 14.4-15.3】

14.4 exportfs命令 14.5 NFS客户端问题 15.1 FTP介绍 15.2/15.3 使用vsftpd搭建ftp

lgsxp ⋅ 今天 ⋅ 0

JeeSite 4.0 功能权限管理基础(Shiro)

Shiro是Apache的一个开源框架,是一个权限管理的框架,实现用户认证、用户授权等。 只要有用户参与一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户...

ThinkGem ⋅ 昨天 ⋅ 0

python f-string 字符串格式化

主要内容 从Python 3.6开始,f-string是格式化字符串的一种很好的新方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快! 在本文的最后,您将了解如何以及为什么今...

阿豪boy ⋅ 昨天 ⋅ 0

Python实现自动登录站点

如果我们想要实现自动登录,那么我们就需要能够驱动浏览器(比如谷歌浏览器)来实现操作,ChromeDriver 刚好能够帮助我们这一点(非谷歌浏览器的驱动有所不同)。 一、确认软件版本 首先我们...

blackfoxya ⋅ 昨天 ⋅ 0

线性回归原理和实现基本认识

一:介绍 定义:线性回归在假设特证满足线性关系,根据给定的训练数据训练一个模型,并用此模型进行预测。为了了解这个定义,我们先举个简单的例子;我们假设一个线性方程 Y=2x+1, x变量为商...

wangxuwei ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部