WTM框架使用技巧之:Layui版本嫁接Vue+ElementUI

快点关注我们吧

作者介绍

庄星睿,现就职于海运物流行业,威海新海丰物流有限公司,IT技术兼管理职务。

从事过winform,wpf技术开发,自2019年接触wtm框架后,热衷使用wtm框架开发物流公司内部软件。

如高度定制化的SOC自备箱管理系统,主要解决日照分公司的新兴海铁联运业务中集装箱管理混乱问题,由于wtm特有的结构化编程理念,快捷高效的使用方式,能够及时有效的满足业务使用,克服以往需求变更快,代码更新慢,无法满足业务发展的弊端,可以说wtm的出现,很好的解决了这些问题。


为什么要这样做

layui版本具备很多优点:组件齐全、ide提醒程度高、代码量少、依赖少、编译快、运行快,非常适合一个人的开发团队

但它也有很多缺点,比如说组件灵活度低、可控性差。

受blazor ssr的思路启发,将vue嫁接进layui版本中,在大部分常规页面中,保留layui的快速高效用法。在极少部分需要大量定制化的页面,采用vue+elementUI的方式编写,既能保证开发效率,又能解决复杂页面编写。

因此本文拿一个页面改造的例子,旨在抛砖引玉。

准备工作

在_Layout中引入包

_Layout.cshtml文件位于Views\Shared\_Layout.cshtml

操作步骤

引入element-ui.css

引入vue.js

引入element-ui.js

<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"><!-- 引入组件库 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

本篇文章使用的vue版本为2.6.14
如下图示

改造一个index.cshtml页面

原页面代码为

@model ReaTms.ViewModel.TruckerVMs.TruckerListVM
@inject IStringLocalizer<Program> Localizer;<wt:searchpanel vm="@Model" reset-btn="true"><wt:row items-per-row="ItemsPerRowEnum.Three"><wt:textbox field="Searcher.TruckerIdentify" /><wt:textbox field="Searcher.TruckerName" /><wt:textbox field="Searcher.TruckerPhone" /></wt:row>
</wt:searchpanel>
<wt:grid vm="@Model" url="/Trucker/Search" />

显示效果为

但我不满意layui的表格,功能太少了,准备使用element-ui的table来替代。

开始改造:

处理原页面

干掉<wt:grid/>组件

将<wt:grid vm="@Model" url="/Trucker/Search" />打上注释,或者干脆直接删掉。

重写<wt:searchpanel/>的搜索按钮点击事件

我们知道,wtm中<wt:searchpanel/>的搜索按钮默认id为wtSearchBtn_@Model.UniqueId(如果对这一点不了解同学,请查看源码src/WalkingTec.Mvvm.TagHelpers.LayUI/Form/SearchPanelTagHelper.cs),那么我们只要拿到这个id,在页面加载的时候,卸载掉框架默认的点击事件,重新绑定一个新的点击事件就可以了。

这里为什么要卸载掉点击事件呢?因为默认的点击事件会调用layui.table去加载数据,而我们在第一步中已经将<wt:grid/>组件移除了,如果不卸载掉默认事件的话,点击按钮会报错。

参照以下代码:

@model ReaTms.ViewModel.TruckerVMs.TruckerListVM
@inject IStringLocalizer<Program> Localizer;<wt:searchpanel vm="@Model" reset-btn="true"><wt:row items-per-row="ItemsPerRowEnum.Three"><wt:textbox field="Searcher.TruckerIdentify" /><wt:textbox field="Searcher.TruckerName" /><wt:textbox field="Searcher.TruckerPhone" /></wt:row>
</wt:searchpanel>
<script>$().ready(() => {$('#wtSearchBtn_@Model.UniqueId').off('click').on('click', e => {e.stopPropagation();//阻止点击事件继续冒泡,使pannel不折叠//查询方法写在这里,下文会继续讲到});});
</script>

定义一个vue的根容器。切记:不要在这个容器中写任何<script>代码,否则vue会报警告

<div id="app">
</div>

创建vue实例,并创建表格数据对象
注意:在cshtml文件中不能使用vue的事件绑定符号@,请使用全称v-on:

  var app = new Vue({el: '#app',data: {TableItems: {} //表格数据对象},methods: {}});

到这一步后,页面的样子是这样的

@model ReaTms.ViewModel.TruckerVMs.TruckerListVM
@inject IStringLocalizer<Program> Localizer;<wt:searchpanel vm="@Model" reset-btn="true"><wt:row items-per-row="ItemsPerRowEnum.Three"><wt:textbox field="Searcher.TruckerIdentify" /><wt:textbox field="Searcher.TruckerName" /><wt:textbox field="Searcher.TruckerPhone" /></wt:row>
</wt:searchpanel>
<div id="app"></div>
<script>$().ready(() => {$('#wtSearchBtn_@Model.UniqueId').off('click').on('click', e => {e.stopPropagation();//阻止点击事件继续冒泡,使pannel不折叠//查询方法写在这里,下文会继续讲到});});var app = new Vue({el: '#app',data: {TableItems: {} //表格数据对象},methods: {}});
</script>

创建element-ui的table
注意这里绑定的是TableItems.Data,这是因为wtm后端传过来的数据是这种格式的。

<div id="app"><el-table :data="TableItems.Data"><el-table-column prop="TruckerName" label="司机" /><el-table-column prop="TruckerPhone" label="电话" /><el-table-column prop="TruckerIdentify" label="身份证" /></el-table>
</div>

给第1步中的搜索按钮编写查询方法。

使用ff.GetFormData(formId)的形式,拿到查询条件的表单数据。

formId可以根据wtm的约定,使用wtForm_@Model.UniqueId拿到。

使用$.post访问后台数据接口,拿到数据后将数据赋值给vue的TableItems对象。

<script>$().ready(() => {$('#wtSearchBtn_@Model.UniqueId').off('click').on('click', e => {e.stopPropagation();//阻止点击事件继续冒泡,使pannel不折叠//查询方法写在这里,下文会继续讲到let data = ff.GetFormData('wtForm_@Model.UniqueId');//拿到查询条件的表单数据$.post('/Trucker/Search', data, resp => {app.TableItems = resp;},'json');});});var app = new Vue({el: '#app',data: {TableItems: {} //表格数据对象},methods: {}});
</script>

至此,我们的页面就跑起来了。

添加分页组件

  • 分别绑定:current-page="TableItems.Page":total="TableItems.Count"

  <el-pagination :current-page="TableItems.Page":total="TableItems.Count"layout="total, sizes, prev, pager, next, jumper"></el-pagination>

再次刷新一下页面看下效果,分页组件能够读取当前页面和总条数了,但所有数据都显示出来了,并没有真正分页。

完善分页组件的功能-分页显示

  • 首先创建一个对象,用来对应wtm中的Searcher,这里只需创建Page和Limit字段就行了,表单字段可以使用对象复制功能,复制过来

    data: {TableItems: {}, //表格数据对象TableSearcher: { //对应wtm中的Searcher"Searcher.Page": 1,"Searcher.Limit": 10,}},
  • 对第6步的查询方法进行封装,封装的过程中,使用$.extend(newobj,oldobj)的方法,将表单数据组装成一个分页查询对象

methods: {onSearch() {//将表单数据复制到this.TableSearcher中,组装成一个完整的查询对象$.extend(this.TableSearcher, ff.GetFormData('wtForm_@Model.UniqueId'));  $.post('/Trucker/Search', this.TableSearcher, resp => {this.TableItems = resp;},'json');}
}

此时页面能够实现分页显示了,但还不能实现跳转页面


完善分页组件的功能-跳转页面

  • 上一步完成后,页面只是实现了分页,但还不能跳转 ,我们继续实现它

  • 创建一个页面跳转函数onPagination(newPage)

    methods: {onSearch() {//将表单数据复制到this.TableSearcher中,组装成一个完整的查询对象$.extend(this.TableSearcher, ff.GetFormData('wtForm_@Model.UniqueId'));$.post('/Trucker/Search', this.TableSearcher, resp => {this.TableItems = resp;},'json');},onPagination(newPage) {this.TableSearcher["Searcher.Page"] = newPage;this.onSearch();}}
  • el-pagination添加跳转事件,v-on:current-change="onPagination"、 v-on:size-change="onPagination"

  <el-pagination :current-page="TableItems.Page":total="TableItems.Count":page-size="10"layout="total, sizes, prev, pager, next, jumper"v-on:current-change="onPagination" v-on:size-change="onPagination"></el-pagination>

此时,已经实现了页面分页,分页跳转



页面的完整代码为

@model ReaTms.ViewModel.TruckerVMs.TruckerListVM
@inject IStringLocalizer<Program> Localizer;<wt:searchpanel vm="@Model" reset-btn="true"><wt:row items-per-row="ItemsPerRowEnum.Three"><wt:textbox field="Searcher.TruckerIdentify" /><wt:textbox field="Searcher.TruckerName" /><wt:textbox field="Searcher.TruckerPhone" /></wt:row>
</wt:searchpanel>
<div id="app"><el-table :data="TableItems.Data"><el-table-column prop="TruckerName" label="司机" /><el-table-column prop="TruckerPhone" label="电话" /><el-table-column prop="TruckerIdentify" label="身份证" /></el-table><el-pagination :current-page="TableItems.Page":total="TableItems.Count":page-size="10"layout="total, sizes, prev, pager, next, jumper"v-on:current-change="onPagination" v-on:size-change="onPagination"></el-pagination>
</div>
<script>$().ready(() => {$('#wtSearchBtn_@Model.UniqueId').off('click').on('click', e => {e.stopPropagation();//阻止点击事件继续冒泡,使pannel不折叠app.onSearch();});});var app = new Vue({el: '#app',data: {TableItems: {}, //表格数据对象TableSearcher: { //对应wtm中的Searcher"Searcher.Page": 1,"Searcher.Limit": 10}},methods: {onSearch() {//将表单数据复制到this.TableSearcher中,组装成一个完整的查询对象$.extend(this.TableSearcher, ff.GetFormData('wtForm_@Model.UniqueId'));$.post('/Trucker/Search', this.TableSearcher, resp => {this.TableItems = resp;},'json');},onPagination(newPage) {this.TableSearcher["Searcher.Page"] = newPage;this.onSearch();}}});
</script>

增加一个Descriptions(描述列表)

想实现效果:点击表格的行,能够在下方实现这行数据的明细

  • 创建当前行的绑定对象SelectedRow

data: {SelectedRow: null,TableItems: {}, //表格数据对象TableSearcher: { //对应wtm中的Searcher"Searcher.Page": 1,"Searcher.Limit": 10}
},
  • 配置el-tablehighlight-current-row,实现点击行自动选中

  • el-tablecurrent-change事件创建回调函数onCurrentChange(currentRow, oldCurrentRow)

    methods: {onSearch() {//将表单数据复制到this.TableSearcher中,组装成一个完整的查询对象$.extend(this.TableSearcher, ff.GetFormData('wtForm_@Model.UniqueId'));$.post('/Trucker/Search', this.TableSearcher, resp => {this.TableItems = resp;},'json');},onPagination(newPage) {this.TableSearcher["Searcher.Page"] = newPage;this.onSearch();},onCurrentChange(currentRow, oldCurrentRow) {this.SelectedRow = currentRow;}}
  • 增加一个el-descriptions

  <el-descriptions title="司机信息" v-if="SelectedRow!=null"><el-descriptions-item label="司机">{{SelectedRow.Trucker}}</el-descriptions-item><el-descriptions-item label="手机号">{{SelectedRow.TruckerPhone}}</el-descriptions-item><el-descriptions-item label="身份证">{{SelectedRow.TruckerIdentify}}</el-descriptions-item><el-descriptions-item label="创建人"><el-tag size="small">{{SelectedRow.CreateBy}}</el-tag></el-descriptions-item><el-descriptions-item label="创建时间">{{SelectedRow.CreateTime}}</el-descriptions-item><el-descriptions-item label="备注">{{SelectedRow.Remark}}</el-descriptions-item></el-descriptions>

此时,页面效果如下图

增加工具栏及权限控制

  1. 使用Wtm.IsAccessable来控制权限

  2. 使用ff.OpenDialog()来打开一个窗口

  <el-row>@if (Model.Wtm.IsAccessable("/Trucker/Create")) {<el-button type="primary" onclick="ff.OpenDialog('/Trucker/Create',1,'创建',1000)">创建</el-button>}</el-row>



此时能够打开窗口创建数据,但创建完成后,数据不能自动刷新。
3. 在控制器中,重写刷新页面的js函数AddCustomScript("app.onSearch();");

        [HttpPost][ActionDescription("Sys.Create")]public ActionResult Create(TruckerVM vm){if (!ModelState.IsValid){return PartialView(vm);}else{vm.DoAdd();if (!ModelState.IsValid){vm.DoReInit();return PartialView(vm);}else{return FFResult().CloseDialog().AddCustomScript("app.onSearch();");}}}

至此,页面能够自动刷新了,其他工具栏按钮可参照该方法创建,复杂功能可参照element的官方案例。

本文仅就这问题谈些浅显的看法,意在抛砖引玉,以就教于各界专家。感谢WTM的作者刘亮,免费授权使用如此优秀的框架,造福大家。

https://wtmdoc.walkingtec.cn/

最终代码

@model ReaTms.ViewModel.TruckerVMs.TruckerListVM
@inject IStringLocalizer<Program> Localizer;<wt:searchpanel vm="@Model" reset-btn="true"><wt:row items-per-row="ItemsPerRowEnum.Three"><wt:textbox field="Searcher.TruckerIdentify" /><wt:textbox field="Searcher.TruckerName" /><wt:textbox field="Searcher.TruckerPhone" /></wt:row>
</wt:searchpanel>
<div id="app"><el-row>@if (Model.Wtm.IsAccessable("/Trucker/Create")) {<el-button type="primary" onclick="ff.OpenDialog('/Trucker/Create',1,'创建',1000)">创建</el-button>}</el-row><el-table :data="TableItems.Data" highlight-current-row v-on:current-change="onCurrentChange"><el-table-column prop="TruckerName" label="司机" /><el-table-column prop="TruckerPhone" label="电话" /><el-table-column prop="TruckerIdentify" label="身份证" /></el-table><el-pagination :current-page="TableItems.Page":total="TableItems.Count":page-size="10"layout="total, sizes, prev, pager, next, jumper"v-on:current-change="onPagination" v-on:size-change="onPagination"></el-pagination><el-descriptions title="司机信息" v-if="SelectedRow!=null"><el-descriptions-item label="司机">{{SelectedRow.TruckerName}}</el-descriptions-item><el-descriptions-item label="手机号">{{SelectedRow.TruckerPhone}}</el-descriptions-item><el-descriptions-item label="身份证">{{SelectedRow.TruckerIdentify}}</el-descriptions-item><el-descriptions-item label="创建人"><el-tag size="small">{{SelectedRow.CreateBy}}</el-tag></el-descriptions-item><el-descriptions-item label="创建时间">{{SelectedRow.CreateTime}}</el-descriptions-item><el-descriptions-item label="备注">{{SelectedRow.Remark}}</el-descriptions-item></el-descriptions>
</div>
<script>$().ready(() => {$('#wtSearchBtn_@Model.UniqueId').off('click').on('click', e => {e.stopPropagation();//阻止点击事件继续冒泡,使pannel不折叠app.onSearch();});});var app = new Vue({el: '#app',data: {SelectedRow: null,TableItems: {}, //表格数据对象TableSearcher: { //对应wtm中的Searcher"Searcher.Page": 1,"Searcher.Limit": 10}},methods: {onSearch() {//将表单数据复制到this.TableSearcher中,组装成一个完整的查询对象$.extend(this.TableSearcher, ff.GetFormData('wtForm_@Model.UniqueId'));$.post('/Trucker/Search', this.TableSearcher, resp => {this.TableItems = resp;},'json');},onPagination(newPage) {this.TableSearcher["Searcher.Page"] = newPage;this.onSearch();},onCurrentChange(currentRow, oldCurrentRow) {this.SelectedRow = currentRow;}}});
</script>

控制器

        #region Create[ActionDescription("Sys.Create")]public ActionResult Create(){var vm = Wtm.CreateVM<TruckerVM>();return PartialView(vm);}[HttpPost][ActionDescription("Sys.Create")]public ActionResult Create(TruckerVM vm){if (!ModelState.IsValid){return PartialView(vm);}else{vm.DoAdd();if (!ModelState.IsValid){vm.DoReInit();return PartialView(vm);}else{return FFResult().CloseDialog().AddCustomScript("app.onSearch();");}}}#endregion     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/298804.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

现在女生的床真的都是这样吗?

1 兰花螳螂喜欢模拟兰花的形态&#xff0c;从而吸引猎物2 女生的床真是这样吗&#xff1f;真的假的啊3 双胞胎姐妹在妈妈肚子里打架概率只有三千万分之一4 用户真正的需求和自以为是的产品设计5 你看我们都尽力给你腾地方了……6 野外生存技能】过滤浑水的方法7 解释一下原理你…

让对话框不显示边框_微信消息“无边框”模式搭配这款壁纸,简直绝了

技能&#xff1a;好运壁纸&#xff0c;微信“无边框”聊天背景图难度系数&#xff1a;1颗星适用系统&#xff1a;安卓&#xff0c;iOS(苹果)今天所长想给大家介绍一组会让人好运爆棚的壁纸&#xff0c;不过&#xff0c;运营妹纸给我分享了一款有趣的聊天背景图&#xff0c;换上…

理解流量监管和整形的关键算法—令牌桶

理解流量监管和整形的关键算法—令牌桶无论是流量监管还是流量整形都提到一个超额流量的问题&#xff0c;而前面已经描述了监管和整形对超额流量的处理方式不同&#xff0c;监管丢弃或者重标记&#xff0c;流量整形是缓存&#xff0c;通过加大延迟的方式发送平滑的数据流量&…

面试官: 平时开发中你用过读写锁吗?

前面实现了一个 带值变更通知能力的字典类(线程不安全)&#xff0c;童鞋们有没有发现演示代码使用了 lock语法糖&#xff0c; 这个有没有问题呢&#xff1f;没背景说个铲铲同程艺龙基础架构部推出的数据获取组件DAL.Connection&#xff0c;我们要做到在切换连接配置时清空数据库…

如何计算一只鸡的表面积?各大专业的奇葩解法

全世界只有3.14 % 的人关注了爆炸吧知识今天&#xff0c;知识君跟大家来算一下一只鸡的表面积吧。数学系

ArrayPool 源码解读之 byte[] 也能池化?

一&#xff1a;背景 1. 讲故事最近在分析一个 dump 的过程中发现其在 gen2 和 LOH 上有不少size较大的free&#xff0c;仔细看了下&#xff0c;这些free生前大多都是模板引擎生成的html片段的byte[]数组&#xff0c;当然这篇我不是来分析dump的&#xff0c;而是来聊一下&#x…

为什么有些人从不点开朋友圈?

全世界只有3.14 % 的人关注了爆炸吧知识真正决定人与人之间的差距的&#xff0c;其实是我们对事物的见识与内心的格局&#xff0c;见识的深浅决定人生的深浅&#xff0c;格局的大小决定了人生之路是宽是窄。今天给大家推荐几个有深度、有想法的公众号&#xff0c;希望能够给你带…

wxPython:登录工具

最近一直在学习Python的基础和一些常用的模块&#xff0c;现在该是付诸实践的时候了。 我打算做的第一个小工具是利用wxPython来创建一个登录小工具&#xff0c;这主要是减轻自己日常工作中的一些负担。具体需求是这样的&#xff0c;在出现工具的UI之后&#xff0c;用户可以选择…

微信 小程序 python 渲染_微信小程序渲染html内容

最近又做了一个新的小程序关于物流订单查询欢迎来体验遇到了一个小问题&#xff1a;数据中返回电话号码的字符串识别出来并且高亮和可以绑定事件。比如数据中包含您的派送员黄xx正在派件&#xff0c;电话&#xff1a;137xxxx41460已经在派送。其中就要识别出137xxxx41460并且绑…

shell oracle查询数组,shell 脚本 ---数组

数组的定义&#xff1a;所谓数组&#xff0c;就是相同数据类型的元素按一定顺序的集合&#xff0c;就是把有限个类型相同的变量用一个名字命令&#xff0c;也就是说这些变量被定义成数组之后&#xff0c;它们就不在有自己的名字了&#xff0c;那么我们怎么找到各个变量或者元素…

Dockerfile 使用 ARG 参数实现构建模板

Dockerfile 使用 ARG 参数实现构建模板IntroDockerfile 里用来表示变量的主要有两个东西&#xff0c;一个是 ENV 代表了环境变量&#xff0c;另外一个则是 ARG 代表是构建 docker 镜像时的一个构建参数&#xff0c;需要在执行 docker build 命令时指定变量的值&#xff0c;最近…

华人AI界痛失“一代宗师”,计算机视觉之父黄煦涛教授去世

全世界只有3.14 % 的人关注了爆炸吧知识美东时间2020年4月25日夜间&#xff0c;华人计算机视觉一代宗师&#xff0c;黄煦涛教授&#xff08;Thomas S. Huang&#xff09;在美国印第安纳州逝世&#xff0c;享年 84 岁。由于他在图像处理、模式识别等计算机视觉领域作出的开创性贡…

oracle 参照完整性,Oracle中用表外键来保证系统参照完整性

欢迎进入Oracle社区论坛&#xff0c;与200万技术人员互动交流 >>进入 Oracle中表的外键是保证系统参照完整性的手段&#xff0c;而参照完整性是指分布在两个表中的列所满足的具有主从性质的约束关系。外键涉及到两个表&#xff0c;其中一个称之为父项表&#xff0c;另一个…

你好,同学!在云端学习最潮的技术吧!

开学季大礼包9月开学了&#xff0c;作为学生的你&#xff0c;有想过在这个数字化年代&#xff0c;学最cool的技术吗&#xff1f;人工智能&#xff0c;物联网&#xff0c;云计算&#xff0c;还有区块链这些互联网产物影响着你的生活&#xff0c;也影响着你将来的职业发展。不论你…

seo关键词互点软件报价_SEO关键词优化收费问题和外包报价问题,一文详解

在竞争日益激烈的市场环境中&#xff0c;企业为了在互联网平台中获得较好的排名&#xff0c;以及实现产品的较好变现&#xff0c;大多数都是使用SEO搜索引擎&#xff0c;因为通过优化关键词可以不断地为用户创造“用户最想得到的”“最匹配”搜索结果&#xff0c;在快速找到心仪…

15张令人震撼的物理动图,看完惊呆了!

全世界只有3.14 % 的人关注了爆炸吧知识比抖音还上瘾看了会让人上瘾的物理动图&#xff0c;赶紧给家里的孩子看看吧&#xff0c;绝对让他开拓眼界&#xff0c;脑洞大开。1.有弹性的岩浆2.高速转动时&#xff0c;因向心力不足而被撕开的的CD&#xff08;慢镜头&#xff09;3.震荡…

linux目录结果说明,Linux目录结构及文件说明

Linux中所有文件都是从(/)根开始的&#xff0c;下面是典型的Linux目录结构说明&#xff1a;/&#xff1a;根目录/bin&#xff1a; binary 主要用来存放可执行文件/sbin&#xff1a; super bin 存放系统管理程序&#xff0c;通常只有管理员才有权限使用/boot&#xff1a; 存放内…

Java wait notify

2019独角兽企业重金招聘Python工程师标准>>> Java wait && notify ‍wait、notify和notifyAll方法是Object类的final native方法&#xff0c;所以这些方法不能被子类重写。 方法 notifyAll() Wakes up all threads that are waiting on this objects monito…

使用ETag协议实现ASP.NET Core API缓存

通常&#xff0c;我们在ASP.NET Core API服务端实现缓存&#xff0c;数据直接从缓存中取出&#xff0c;返回给客户端&#xff0c;以便加快响应速度。但是这样的做法&#xff0c;解决不了数据传输到客户端需要占用带宽带来的性能问题。这时&#xff0c;可以尝试使用ETag。ETag协…