看了vue的数据双向绑定原理后对于其中的'指令的解析'
有很深的印象,觉得可以运用到实际项目中,对目前的公司中的中英文页面进行改进(兼容IE8);
github (求★)
中英文页面历史版本优缺点分析
1.最开始的时候中英文分别是用两个html去写;
a_cn.html
<div class="unitDiv_Cn">
<label class="labelClass_Cn">防闪频率:</label>
<input class="inputClass_Cn" type="text">
</div>
a_en.html
<div class="unitDiv_En">
<label class="labelClass_En">Flicker frequency:</label>
<input class="inputClass_En" type="text">
</div>
优点:
由于对同一个词的中文和英文描述长度不一样,可以分别在两个html中分别定义各自的class去控制样式缺点:
- 文字描述嵌入在html中,不利用统一管理
- 修改代码繁琐,改一个问题的时候可能需要修改两次
- 增大了服务器中的文件体积
2.改进后利用jq同一动态渲染;(这边主要是通过将需要渲染文字的元素定义好id,再定义好id与文字的映射关系,最后通过jq的选择器进行统一渲染)
a.html
<div class="unitDiv_En">
<label class="labelClass_En" id="labFlickerFrequency"></label>
<input class="inputClass_En" type="text">
</div>
cn.js
...
language.label={
labFlickerFrequency:'防闪频率:',
}
en.js
...
language.label={
labFlickerFrequency:'Flicker frequency:',
}
优点:
- 将两个文件合并成同一个文件,减小了服务器中的文件体积
- 由于合并为了一个文件,对于代码的修复,只需要改一次就好
- 剥离出html中的文字描述,统一管理,利用js动态渲染
缺点:
- 合并为同一个文件后样式会以英文描述的为主
例如:这里很明显能看出中文的页面是按照英文的样式来渲染的,这样看起来不太舒服;
- 所有文字都是一次性渲染,有些隐藏元素的文字也会进行渲染,影响首屏渲染速度
新版中英文页面的改进
在改进版本的基础上,不通过jq的选择器进行渲染,而是在每个需要渲染文字的元素上添加自定义属性,也就是我们的指令:inf-text='xxx'
,再通过类似vue的方式进行初始化
流程:
将每个dom元素提取出来->
解析指令->
再去数据中查找文字->
进行文字渲染->
删除自定义属性->
最后再将dom元素一个个重新渲染到页面上;
(参考vue源码的指令解析即可,我这边为了满足项目需求,移植的时候简化了不少,而且兼容了IE8)
inf-class='xxx'
指令来控制我们的样式inf-value='xxx'
来控制value属性的中英文(这里主要是用在input[type=button]
上)inf-title='xxx'
来控制title属性的中英文inf-alt='xxx'
来控制alt属性的中英文
源码就不去解析了(有兴趣可以看看github上的代码,有注释,而且代码也是比较简单),直接贴使用代码:
<div id="app">
<div class="unitDiv">
<label inf-class="labelClass" inf-title="languageData.lab.a" inf-text="languageData.lab.a"></label>
<input inf-class="inputClass" type="text" inf-value="inputClass">
</div>
<div class="unitDiv">
<label inf-class="labelClass" inf-text="languageData.lab.b"></label>
<input inf-class="inputClass" type="text" inf-value="inputClass">
</div>
<div class="unitDiv">
<label inf-class="labelClass" inf-text="languageData.lab.c"></label>
<input inf-class="inputClass" type="text" inf-value="inputClass">
</div>
<div class="unitDiv">
<label inf-class="labelClass" inf-text="languageData.lab.d"></label>
<input inf-class="inputClass" type="text" inf-value="inputClass">
</div>
<div class="unitDiv">
<label inf-class="labelClass" inf-text="languageData.lab.e"></label>
<input inf-class="inputClass" type="text" inf-value="inputClass">
</div>
<div class="unitDiv">
<label inf-class="labelClass" inf-text="languageData.lab.f"></label>
<input inf-class="inputClass" type="text" inf-value="inputClass">
</div>
</div>
<div id="app2">
<select>
<option value="0" inf-text='languageData.sel.g'></option>
<option value="1" inf-text='languageData.sel.h'></option>
</select>
</div>
<select id="switch">
<option value=0 selected>英文</option>
<option value=1>中文</option>
</select>
<script type="text/javascript" src="languageData.js"></script>
<script type="text/javascript" src="languageRender.js"></script>
<script>
var lan=document.getElementById('switch').value;
var languageObj=getLanguage('module1');
var languageRenderCtx=new languageRender({
el: ['app','app2'],
lan:lan,
data: {
languageData: languageObj,
labelClass:['label_en','label_cn'],
inputClass:['input_en','input_cn']
},
beforeRender:function(){
this.option.data.languageData.lab.a=['BLC:','白平衡:']
}
})
document.getElementById('switch').onchange=function(){
languageRenderCtx.setLan(Number(this.value));
}
</script>
languageData.js:
function getLanguage(moduleName) {
var data = {};
if ('module1' == moduleName) {
data = {
lab: {
a: ['Flicker frequency:', '防闪频率:'],
b: ['WDR:', '宽动态:'],
c: ['FaceTargetBrightness:', '人脸目标亮度:'],
d: ['FaceExposureInterval(s):', '人脸曝光间隔(s):'],
e: ['IlluminationCondition:', '光照条件:'],
f: ['HLC:', '背光补偿:']
},
sel: {
g: ['Auto', '自动'],
h: ['Manual', '手动']
}
}
}
return data;
}
ps:里面的languageData.lab.a,languageData.lab.b...这种a,b,c...命名方式只是为了方便演示,真正用的时候肯定不能这样命名
- getLanguage为获取文字描述的函数,参数名为模块名
- languageRender为具体的构造器函数
- lan为0代表英文,1代表中文,这里根据具体自己的业务需求进行修改
- el:代表的是需要渲染的dom的包裹元素id,只所以我这里是用数组去表示,因为并不是页面的所有dom都需要文字渲染,而且渲染的原理是对于dom元素二次渲染,为了减少不必要的开销,用数组去传入需要渲染的dom的包裹元素id即可
el:['app','app2']
,如果只有一个包裹元素内的dom需要渲染可以直接填id名,即el:'app'
- data为的数据容器对象,languageData为语言文字对象,其余的根据自己的需求进行填写,这里我们也只是需要动态控制class即可;
优点:
- 这样我们就做到了中英文和样式的动态渲染
-
这里我还另外增加了一个beforeRender的hook函数,可以更好的实现页面文字的定制修改
例如:
new languageRender({ ... beforeRender:function(){ this.data.languageData.lab.a=['BLC','白平衡'][lan] } })
- 如果整个页面需要渲染文字的dom元素太多,而且有些dom的最开始是隐藏的(弹框),我们可以进行
懒加载
加快首屏渲染速度,等首屏渲染好了后,再new languageRender函数继续渲染即可(当然这个dom是和已经渲染的dom没有包含与被包含的关系) -
将
数据绑定
结合起来,只需要手动控制数据即可立即渲染页面,不用再重新进入。languageRenderCtx.set('languageData.lab.a','liuzj')
同时也提供了统一切换中英文的接口
document.getElementById('switch').onchange=function(){ languageRenderCtx.setLan(Number(this.value)) }
- 利于语言的扩展,例如需要再加入新的语言,只需要在数组中加入即可,然后再通过lan进行选择
lab: {
a: ['Flicker frequency:','防闪频率:','防閃頻率','फ्लैश प्रूफ आवृत्ति'],
},
新旧版本比较
老版本:
新版本:(一次性渲染)
新版本:(分开渲染)
- 从上面看出改良后的版本速度上貌似也没快多少,但是功能性方面个人觉得确实方便了不少;
- 从上面可以看出部分渲染和一次性渲染貌似并没有什么差别,我个人觉得这种情况适合有更多的隐藏页面存在的时候性能上应该是提升不少,目前这个页面我第二次渲染的只有
弹出框
和格式化页面
- 我们可以分别打印出划分的模块的渲染时间,这样更方便我们合理的分配渲染顺序,也可以知道哪个模块渲染时间长,再下手优化;
例如:
模块1:
模块2
模块3
模块4
- 页面可以快速切换中英文页面
ps:对于IE8我这边也试过了,是可以的,就不放截图了
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。