vue 与 dot 渲染表格 时间复杂度分析
doT.js,用过的都知道,渲染表格贼快。doT.js特点是快,小,无依赖其他插件。压缩版仅有4K大小。
- dot的基本语法:
{{= }} for interpolation
{{ }} for evaluation
{{~ }} for array iteration
{{? }} for conditionals
{{! }} for interpolation with encoding
{{# }} for compile-time evaluation/includes and partials
{{## #}} for compile-time defines
是不是看着和vue有点像? - dot的基本用法(基本上分为三个部分你就能运用到项目中):
在.cshtml中:<script id="staticTable_Tmp" type="text/x-dot-template">
<table class="fund-table">
<thead>
<tr style="line-height:40px">
<td style="padding-left:20px !important; width:100px">功能分类</td>
<td style="padding-left:20px !important; width:90px">登录跳转次数</td>
<td style="text-align:right;width: 84px!important;">频次</td>
<td style="text-align:right; width: 80px!important;">百分比</td>
</tr>
</thead>
</table>
<div class="tableScrollContainer" style="">
<table class="fund-table">
<tbody>
{{ if(it.length>0 ) { }}
{{ for(prop in it){ }}
<tr style="height:33px;line-height:32px">
<td style="padding-left:20px !important; width:100px">
{{? it[prop].Category.length <= 28 }}
<a href="{{= it[prop].Url }}" target="_blank" class="stockName detailJump" title="{{= it[prop].Url }}">{{= it[prop].Category }}</a>
{{??}}
<a href="{{= it[prop].Url }}" target="_blank" class="stockName detailJump" title="{{= it[prop].Url }}">{{! it[prop].Category.substring(0,26)+'..' }}</a>
{{?}}
</td>
<td style="text-align:right;cursor: default;width: 98px!important;">{{= it[prop].FromLogin }}</td>
<td style="text-align:right;cursor: default;width: 90px!important;">
{{?it[prop].CountLink.length>0}}
<a href="{{= it[prop].CountLink }}" target="_blank">{{= it[prop].Frequency }}</a>
{{??}}
{{= it[prop].Frequency }}
{{?}}
</td>
<td style="text-align:right;cursor: default;width: 80px!important;">{{= it[prop].Percent }}</td>
</tr>
{{ } }}
{{ } else{ }}
<tr>
<td>无数据</td>
</tr>
{{ } }}
</tbody>
</table>
</div>
</script>
这部分就是单纯的写在一个js标签中,看着上面的id,必须为ID。然后,在你需要布局的地方写下<div class="staticTableHook ">
</div>
这里就是挂载上面模板的地方
最后的就是在我们js获取数据源的地方,将请求过来的json数据与模板绑定到dot上
var interText = doT.template($("#" + tmpName).text());
$("." + className).html(interText(res));
这样就能够渲染到界面上了,但dot里面没有排序,插件,搜索,就单单的渲染一个表格。
3. 同样的,用vue也做了一个表格渲染的模板,代码如下:
define(['Vue'], function(Vue){
Vue.component('tra-common',{
props:['it','list'],
template: `
<div class='componentContainer' v-if="it != null">
<div class='fund-panel'>
<div class="title">
<span class="fund-title-inline">交易申请表</span>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">所属产品</div>
<div class="fund-col-7 spanStyle">
<span>{{it.FundName}} </span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">交易方式</div>
<div class="fund-col-7 spanStyle">
<span>{{it.TransactionMeans}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">证券名称</div>
<div class="fund-col-7 spanStyle">
<span>{{it.SecurityName}} </span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">发行人性质</div>
<div class="fund-col-7 spanStyle">
<span>{{it.IssuerNature}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">发行期代码</div>
<div class="fund-col-7 spanStyle">
<span>{{it.IssuingCode||"--"}} </span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">正式代码</div>
<div class="fund-col-7 spanStyle">
<span>{{it.SecurityCode||"--"}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">资产类别</div>
<div class="fund-col-7 spanStyle">
<span>{{it.AssetClass}} </span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">主体评级</div>
<div class="fund-col-7 spanStyle">
<span>{{it.IssuerRating}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">债券属性</div>
<div class="fund-col-7 spanStyle">
<span>{{it.WindIndustry}} </span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">债券评级</div>
<div class="fund-col-7 spanStyle">
<span>{{it.DebtRating||"--"}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">票面利率</div>
<div class="fund-col-7 spanStyle">
<span>{{it.CouponRate}}</span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">存续期限</div>
<div class="fund-col-7 spanStyle">
<span>{{it.RemainTerm}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">发行规模(亿元)</div>
<div class="fund-col-7 spanStyle">
<span>{{it.IssueScale}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">买卖方向</div>
<div class="fund-col-7 spanStyle">
<span>{{it.TransactionDirection}} </span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">预计交易时间</div>
<div class="fund-col-7 spanStyle">
<span>{{it.EstimatedTransactionTime}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">交易平台</div>
<div class="fund-col-7 spanStyle">
<span>{{it.TradingPlatform}} </span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">预计交易价格(元)</div>
<div class="fund-col-7 spanStyle">
<span>{{it.TransactionPriceMin}}-{{it.TransactionPriceMax}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5 ">预计交易规模(万元)</div>
<div class="fund-col-7 spanStyle">
<span>{{it.TransactionVolume}} </span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5 ">收益率</div>
<div class="fund-col-7 spanStyle">
<span>{{it.YtmMin}}-{{it.YtmMax}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">代持方式</div>
<div class="fund-col-7 spanStyle">
<span>{{it.AgreementMeans}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5">其他需要载明的事项</div>
<div class="fund-col-7 spanStyle ">
<span>{{it.Remarks}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-12">
<div class="fund-selpanel-title fund-label" style='width:210px;float:left'>附件</div>
<div class="fund-col-7 spanStyle">
<div>
<span v-if="list[0]==='--'">
{{list[0]}}
</span>
<span style = "margin-bottom:8px;display:inline-block" v-for="(item,index) in list" :key='index'>
<a class="fund-link" :href ="'/FileManage/FilePreview?fileid='+item.FileId"> {{item.FileName }}</a>
</span>
</div>
</div>
</div>
</div>
</div>
<div class='fund-panel' style='margin-top:10px'>
<div class="fund-row">
<div class="title">
<span class="fund-title-inline">审核明细</span>
</div>
</div>
<div v-if="it.ApplicationOperList.length>0">
<div v-for="item in it.ApplicationOperList">
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5 ">审核人</div>
<div class="fund-col-7 spanStyle">
<span>{{item.Operator}} </span>
</div>
</div>
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5 ">审核时间</div>
<div class="fund-col-7 spanStyle">
<span>{{item.OperationTime}}</span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-6">
<div class="fund-selpanel-title fund-label fund-col-5 ">审核结果</div>
<div class="fund-col-7 spanStyle">
<span>{{item.AuditResult}} </span>
</div>
</div>
</div>
<div class="fund-row">
<div class="fund-col-12">
<div class="fund-selpanel-title fund-label fund-col-2 ">审核意见</div>
<div class="fund-col-9 spanStyle" style='padding-left:42px'>
<span>{{item.AuditOpinion}}</span>
</div>
</div>
</div>
</div>
</div>
<div v-else>暂无审核意见</span></div>
</div>
</div>
`
}),
Vue.component('fix-thead-table',{
props:['datatable'],
computed: {
col:function(){
return this.datatable.thead.length;
},
field:function(){
return this.datatable.fields;
},
thead:function(){
return this.datatable.thead;
},
tbody:function(){
return this.datatable.tbody
},
theadWidth:function (param) {
var Twidth=null;
$.each(this.datatable.thead,function(index,value){
if(value.width){
Twidth +=value.width.split('p')[0]-0+10;
}
})
return (Twidth+30)+"px"
}
},
beforeCreate:function() {
console.time("vue")
console.time("Updata-vue")
},
mounted:function () {
console.timeEnd("vue")
console.log(1)
},
updated() {
console.log(2)
console.timeEnd("Updata-vue")
},
template:`
<div>
<table class="fund-table thead" :style="{width:theadWidth}">
<thead :class=''>
<tr>
<td v-for="item in thead" :style="{textAlign:item.align,width:item.width}">
{{item.title}}
</td>
</tr>
</thead>
</table>
<div :style="{overflow:'auto',height:datatable.height,width:theadWidth,overflowX: 'hidden' }">
<table class="fund-table tbody" :style="{width:theadWidth}">
<tbody>
//注意这里(第一种)↓
<tr v-for='item in tbody'>
<td>
{{item.Category}}
</td><td>
{{item.FromLogin}}
</td><td>
{{item.Frequency}}
</td><td>
{{item.Percent}}
</td>
</tr>
//注意这里↑
//注意这里(第二种)↓
<tr v-for='item in tbody'>
<td v-for = '(i,index) in thead'
:style="{width:i.width,textAlign:i.align,overflow:'hidden',whiteSpace:'nowrap',textOverflow:'ellipsis'}">
<a v-if='item[i.link]↓↓▩' :href="item[i.link]">
{{item[i.field]}}
</a>
<span v-else>
{{item[i.field]}}
</span>
</td>
</tr>
//注意这里↑
</tbody>
</table>
</div>
</div>
`
})
})
这是一个公用组件,写的是一个固定表头的table,传入一个表格的基本数据,然后渲染出来。没什么大问题,原来设想的是做一个datatables组件一样的东西,传入一些基本的数据就可以,实现自定义的配置出一个表格。比如td的宽度,text-align,thead,link地址。后来说是第二种方法双层循环会不会渲染很慢?后来就展开了一系列表格性能检测,先顺便展示一下vue生成表格的核心方法。
var app = new Vue({
el:'#app',
data:{
datatable:[{
thead:[{
title:'功能分类',
align:'left',
field:'Category',
width:"110px",
link :'Url'
},
{
title:'登录跳转次数',
align:'right',
field:'FromLogin',
width:"90px",
},
{
title:'频次',
align:'right',
field:'Frequency',
width:"105px",
link :'CountLink'
},{
title:'百分比',
align:'right',
field:'Percent',
width:"120px"
}],
tbody:{},
height:'264px'
}],
tbody:{}
}]
},
beforeCreate() {
console.time("data")
},
mounted() {
console.timeEnd("data")
},
})
这里的title就是表格的头部显示。field就是第一种方法中我们循环的时候需要的字段。通过<tr v-for='item in tbody'>
<td v-for = '(i,index) in thead'
:style="{width:i.width,textAlign:i.align,overflow:'hidden',whiteSpace:'nowrap',textOverflow:'ellipsis'}">
<a v-if='item[i.link]↓↓▩' :href="item[i.link]">
{{item[i.field]}}
</a>
<span v-else>
{{item[i.field]}}
</span>
</td>
</tr>
双层循环动态的生成td,这样我们只需要配置好一个表格的基本属性,就可以动态的生成不定列表格。同样双层循环渲染td也带来了很大的时间消耗。
beforeCreate:function() {
console.time("vue")
console.time("Updata-vue")
},
mounted:function () {
console.timeEnd("vue")
},
beforUpdata(){
console.time("Updata2")
},
updated() {
console.timeEnd("Updata-vue")
console.timeEnd("Updata2")
},
这里就是说创建组件到挂载成功,以及更新数据渲染成功,分别打印出时间。
可以看到当加载组件是vue:1.9 ms,然后更新完data以后,重新渲染表格Updata-vue:56.7ms.我们再来看看dot的渲染时间:
renderList: function (tmpName, className, res) {
return new Promise(function (resolve, reject) {
console.time("dot")
var interText = doT.template($("#" + tmpName).text());
$("." + className).html(interText(res));
$(".behaviorAnalysis").unblock();
resolve();
console.timeEnd("dot")
});
},
代码是上面的,运行结果:,
这不是偶然结果,我运行了很多次,vue在挂载组件的时候可能很快,但按照我这样写的双循环去渲染td的时候就是很消耗时间了。但请看到最后–>
- vue重点是在组件复用,数据交互,我同时应用了三次组件在一个el:#app下,同样,我也调用了dot的模板,做了三次表格渲染。界面数据条数是不一样的:
-这个是运行的结果
数据的多少对dot结果有影响,但这里我就有点不懂了
最后那个是beforeupdate-updated的时间。
可以清楚的看到dot渲染的时间和数据列有关系,但对于vue来说,组件挂载了一次以后,后面的时间都成了0ms,可能是对vue了解的不多。 updata2都是0,这一点我以为它会每个组件渲染的时候都回去执行一次呢!!而且可以看到三个表格,结构都是不一样的。这是我这次code中不理解的地方,先记录下来。如果有哪位有耐心读到这里,多谢帮忙解惑! - 疑问的地方:vue的这个监听器我是可以理解,就是created到mounted,但后面的那两次vue:0ms是怎么回事,如果说组件只创建一次的话,那怎么就跑了三次监听器?也就是第一个红方框的那三个数据。
- 还有后面的update-vue后面的两个怎么是0ms
- updata-vue 这里时间这么长是代码写的有问题,还是vue这样用就需要这么长的时间?
-
//注意这里(第一种)↓
<tr v-for='item in tbody'>
<td>
{{item.Category}}
</td><td>
{{item.FromLogin}}
</td><td>
{{item.Frequency}}
</td><td>
{{item.Percent}}
</td>
</tr>
//注意这里↑
我曾把渲染的过程先用字段代替,不走双循环,需要的时间同样也是50多ms.