前端

目录结构及模版语法及其他文档

rails目录结构: https://ruby-china.org/topics/2432

rails 模板语法 :https://ihower.tw/rails4/actionview.html 可能需要VPN访问

Rails 布局和视图渲染 :http://guides.ruby-china.org/layouts_and_rendering.html

scss 语法: http://sass.bootcss.com/

jquery ujs: https://github.com/rails/jquery-ujs

git:https://git-scm.com/book/zh/v2

布局及模版继承

app/views/layouts/sample_layout.html.erb

一个通常的布局文件会包含以下block.

...<head>...

如此我们可以在具体的页面使用如下方式引入外部样式和脚本或者嵌入样式和脚本,使得样式和脚本在html里的合理位置。

1
2
3
4
5
6
7
8
9
10
11
...
<% content_for :extro_styles do %>
<%= stylesheet_link_tag "jquery.multiselect2side_2.css", :media => "all" %>
<style>...</style>
<% end %>
...
<% content_for :extro_scripts do %>
<script src="/assets/jquery.sparkline.js"></script>
<%= javascript_include_tag "jquery.multiselect2side_2.js" %>
<script>...</script>
...`

以上代码在页面的模版的位置无关紧要,最终在html里的位置已经在布局中声明。

静态文件的组织

样式

app/assets/stylesheets/application.css

application.css require了网站公共的样式包含.css .scss 在调试模式中分别引入,在生产环境将合并压缩在application.css里。

如新增模块可按application.css的格式新增css并require该模块单独使用的样式,并在该模块的layout里引入,放在application.css引入的下面。

脚本

app/assets/javascripts/application.js

与样式同理。

图片

如新增模块,新建文件夹以便合理组织图片。

partial及.js.erb

partial是为了在不同页面渲染相同的模版片段(如模块的公用菜单等),partial的命名均以下划线开头,样式和脚本最好在模版里的block写入。

.js.erb 是响应ajax请求并返回javascript类型数据,一般包含如下类似内容

1
$("#container_id").html(<%=j(render:partial=>'/new_card_analysis/people_consume_ability_vs_date_left')%>")

这部分代码逻辑是选择页面上的容器元素并替换元素里的html,所以建议不要在partial里写样式和脚本,多次ajax请求会重复渲染相同的样式和脚本(如对相同的元素多次绑定相同事件此类无意义的代码),如需要ajax请求执行js可以在.js.erb 因为返回的是javascript类型数据,脚本写在这里更为合适而不是替换容器元素的html同时包含脚本。

关于jquery ujs

https://github.com/rails/jquery-ujs ujs是rails的gem包,安装好后会在增加jquery_ujs.js文件,项目里的’application.js’已引入//= require jquery_ujs,ujs默认绑定了一些事件,具体参见https://github.com/rails/jquery-ujs/blob/master/src/rails.js。

常用的ajax表单提交可以<%= form_for ... %>:remote=>true<% end %> 如此最终的form标签包含data-remote=”true”(直接在html form标签加这个属性也是可以的),表单提交后会执行类似

1
2

$.ajax({method:"post",dataType:"script",....})

基于jquery发起一个ajax请求,并声明请求的格式为script,后端可以通过.js.erb响应此请求也可以在action里声明返回的数据类型是javascript并渲染其他路径的模版或者直接返回javascript字符串。

如根据需求除了需要执行.js.erb里的响应内容外还需要执行页面上其他交互可以手动写$.ajax请求而不必拘泥于ujs默认绑定的事件(此时需要去掉ujs的属性以避免重复绑定)。 $.ajax({method:”post”,dataType:”script”,….}).done(function(){ …//其他交互逻辑。 })

关于AJAX

数据类型优先方案是采用json格式的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$button.on("click",function(e){
e.preventDefault();//阻止此元素的浏览器默认行为(锚链接行为,表单提交行为)
var $this = $(this),form = this.form;//表单元素会有.form属性指向所在表单
var params = {url:"",processData:processData,method:"post",dataType:"json",data:data,beforeSend:function(jqXHR,settings){
$this.data('text',$this.text());//保存按钮默认文字
$this.prop('disable',true);//避免提交过程中多次点击
$this.text('提交中...');
},....}
//processData 布尔值,ajax请求默认为true,如果表单数据较少
//data = {key1:$element1.val(),key2:$element2.val()}
//processData此时params就不需增加processData属性维持默认jquery内部将对象字面量转换成"key1=val1&key2=val2"的形式发送给后端
// 若表单数据较多
// data = $(form).serialize() 直接将表单中所有表单元素转换为"key1=val1&key2=val2"的形式
// processData 此时值需要为false
$.ajax(params).done(function(data, textStatus, jqXHR){
//data 根据请求dataType不同类型不同 "html"为字符串,"json"为对象字面量
//html 一般执行$containerElement.html(data);
}).fail(function(jqXHR, textStatus, errorThrown){
alert(textStatus);// 提示错误,后端需要返回http code 非200,根据错误类型
}).always(function(data|jqXHR, textStatus, jqXHR|errorThrown){
//无论请求成功或失败
$this.prop('disable',false); //恢复可点击状态
$this.text($this.data('text')); //恢复默认文字
});
});

关于“删除”:

<a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>

上面的例子通过data-method="delete"属性绑定事件,当用户点击发起一个ajax请求 http method为delete(我们可以将delete替换为post,避免使用get请求以免在浏览器直接打开执行”删除”操作),在此之前因为有data-confirm存在会先调用window.confirm 浏览器打开一个确认对话框询问用户是否要执行此操作,在执行删除操作时我们一般都需要用户进行确认以避免用户误点击而删除了数据。

最近公司有同事在移动端网页用到flexiable.js

1
2
3
4
5
6
7
8
9
10
11
12
13
 if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}

此段代码如果ua不包含“iphone”,那么采用1dpr,理由是

淘宝的做法是只管iOS,安卓一律把dpr设为1,官方的说法是安卓的厂商会自己修改dpr,导致安卓上的 window. devicePixelRatio 是假的。

出处 但如果安卓的devicePixelRatio 是真实的且大于1则没有适用此方案。 再看另一处代码,

1
2
3
4
5
6
7
8
 if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[1]);
dpr = parseInt(1 / scale);
}
}

如果已经自己设置了meta viewport initial-scale=1.0 则scale为1,dpr也只能为1。 如果可根据devicePixelRatio动态设置initial-scale那么可解决1px边框的问题,但以上两种情况下scale只能为1. 再接着看另一处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
```

如果width / dpr > 540 则分辨率宽度按540处理,然而我们结合[友盟指数](http://tip.umeng.com/uploads/data_report/mobile_phone_report_.pdf)来看,540已经不在友盟的统计范围,也就是排除在主流分辨率之外了。也就是说在目前主流分辨率下html font-size就是54px,并且这里存在的问题是参照值应该取设计稿的宽度(px)而不是固定540,如果想要灵活地根据设计稿来设置最大宽度可以使用[hotcss](https://github.com/imochen/hotcss),与flexiable是类似方案在meta上可设置max-width,且scss,less上也可以设置设计稿的宽度。 那么flexiable还适用于现在的开发么?结合hotcss所给出的案例地址还有网易新闻来看还是有几个案例在使用的,然而天猫和淘宝本身没在使用,那么此时想问为什么? 我先回答flexiable是怎么解决适配的问题吧 1,根据不同的dpr设置html元素的基础字号像素为单位,以此来达到在元素上设置rem为单位的尺寸时元素大小边距等的缩放。 2,由于1动态改变了html基础字号,我们又需要\[data-dpr\]来设置不同dpr下元素字号,这是为1解决的问题而产生的新问题买单。 3,根据不同的dpr设置scale,解决dpr>1时1px边框会比dpr=1时稍粗的问题,但是前面我们看到scale在大多数情况下就是1. 我们再来看看其他问题[ios使用scale后,调用高德地图,地图也会被缩掉,怎么解决?](https://github.com/amfe/lib-flexible/issues/54) [微信二维码识别相关](https://github.com/amfe/article/issues/17#issuecomment-259130658) 这两个问题最后给的解决办法还是将dpr设置为1来解决。 那么flexiable实际上的作用只有我上面列的三项中的第一项了。我再来回答为什么不用flexiable; 1,1像素边框的问题可以用

``` css
.scale{
position: relative;
}
.scale:after{
content:"";
position: absolute;
bottom:0px;
left:0px;
right:0px;
border-bottom:1px solid #ddd;
-webkit-transform:scaleY(.5);
-webkit-transform-origin:0 0;
}

或者干脆不解决。对此我的观点是1px到底采用1个,2个还是N个物理像素那是浏览器所采用的方案。天猫和淘宝现在都宽高边距用px了,即便结果是普通安卓机上和retina上元素看起来大小不一样。 2,对于页面上较多绝对定位的,我们可以直接<meta name="viewport" content="width:设计稿尺寸(px)"> 来解决。 那么flexiable还有理由用吗? 有,如果你的设计稿尺寸是540或者你灵活地根据设计稿设置了最大宽度,那么屏幕宽度对于小于设计稿宽度的设备,基于动态的设置html font-size,元素的尺寸和边距可以很好的缩小。当然这里的前提是设计稿的宽度应是主流移动设备的屏幕宽度,如果设计稿的宽度就小那么你想想你到底用到flexiable的哪一点吧?

历史:

如果我没记错的话,script defer 最开始是IE提出,其他浏览器厂商随后跟进提供支持。

用法:

defer用来声明该脚本不包含document.write 以使浏览器可以异步的加载(异步加载不是关键,其实最重要的是不阻塞html的解析,这也就是为什么脚本里不能含有document.write),然后按照声明defer的script标签的顺序来执行(这是与async标签的不同)。 需要记住的是,标明defer的script 必须是个外部引入的脚本而不能是inline script。 @see http://dev.w3.org/html5/spec/scripting-1.html#attr-script-defer

The defer and async attributes must not be specified if the src attribute is not present.

兼容性:

mozilla 开发人员中心 提到:

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 1.0 1.0 (1.7 or earlier) (Yes) (Yes) (Yes)
async attribute (Yes) 3.6 (1.9.2) 10 Not supported (Yes)
defer attribute (Yes) 3.5 (1.9.1) 4 (follows a spec of its own) Not supported (Yes)
10 (by the spec)

Chrome                            Firefox(Gecko)       Internet Explorer   Opera        Safari

crossorigin attribute 30.0 Chromium Bug 159566 13.0 (13) bug 696301 Not supported 12.50 (Yes)
(WebKit bug 81438)

@see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script?redirectlocale=en-US&redirectslug=HTML%2FElement%2Fscript 尽管上面提到IE 从IE4开始支持defer,但它遵循的是IE自家的定义,从10才开始按照规范。 Internet Explorer 5.1.7 Mac下的bug. http://www.websiteoptimization.com/speed/tweak/defer/test/“ target=”_blank”>Internet Explorer 5.1.7 Mac shows sequential execution despite the defer attribute stackoverflow 上有提到:

defer works with chrome , firefox , ie > 7 and Safari

@see http://stackoverflow.com/questions/5250412/how-exactly-does-script-defer-defer-work 当然PO主犯了个严重的错误,在inline script 用defer属性。 然而问题还没有完, https://github.com/h5bp/lazyweb-requests/issues/42#issuecomment-1901803

And the first script modifies the dom with appendChild, innerHTML, (etc.), the second script can start executing before the first one has finished. Thus, a dependency between the two will break.

我看了上面这个issues两遍(E文实在糟糕),这个问题我自己还没遇到过,之前我都是jquery直接在head里加载完,剩下的jquery 插件才加defer,主要是我不会在dom ready之前去改变文档的结构。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×