从后端到前端之Vue(四)小试牛刀——真实项目的应用(树、tab、数据列表和分页)
学以致用嘛,学了这么多,在真实项目里面怎么应用呢?带着问题去学习才是最快的学习方式。还是以前的那个项目,前后端分离,现在把前端换成vue的,暂时采用脚本化的方式,然后在尝试工程化的方式。
现在先实现功能节点(树)、动态tab、数据列表、分页这几个主要功能。在前面几章里面代码都已经介绍了,好吧分页没说,不过也比较简单了,加个模板,把数据接上,再加个事件就可以了。
一、同一段代码,一个项目里实现多个数据列表
先看一下效果:GIF动图,1.5s一张不要太着急。另外截图没截好,不太清晰大家多担待。(左上角是一个水印。)
二、同样的代码,在实现其他项目实现各种数据列表
动图里面只演示了两个模块(页面),其实不仅可以实现这两个页面,所有的基础列表页面都可以实现,即使换一个新的项目,也只需要改几个参数就行(不需要修改代码),如下图:
三、页面级的抽象
实现这些功能,(前端)的代码(html+vue)不超过300行(只需要一段,不用各种copy)。首先是vue很给力,代码上面可以做到很精简,另一个就是面向对象的基础——抽象!
虽然功能模块非常多,但是数据列表的模式是一样的,区别就是——字段不一样,其他的还不都是一样的吗?所以我们可以针对所有的数据列表需求做一个抽象,把共同的功能拿出来做成代码(或者组件),把差异化的需求也拿出来做成json包。这样代码就一样了,不用一次一次的copy。我们只需要维护好json包就可以。
这么做有几大优点:
1、 减少bug的出现机会,因为代码很少,想出bug都难。而且会经过很多业务模块、项目的测试,可以及时发现bug。
2、 便于修改bug,因为代码就一处,改了一处就是所有(项目)这类的bug都被修改了。
3、 减少了很多代码量,让程序员有更多的时间休息,,,,哦不对,是更多的时间去思考更复杂的业务逻辑如何实现。
4、 便于升级,因为代码只有一处,想要升级修改这一处就好,其他所有的列表功能就都跟着一起升级了。
5、 便于入门学习,就这一处代码,还学不会?
四、完整代码
1、页面、模板
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>树和列表以及分页</title>
<meta charset="utf-8" />
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="vue-resource.min.js"></script>
<link type="text/css" rel="stylesheet" media="screen" href="/Manage/css/mangoGlobal.css">
<link type="text/css" rel="stylesheet" media="screen" href="/Manage/css/mis-style-p.css">
<link type="text/css" rel="stylesheet" media="screen" href="/Manage/css/MisStyle_v2.css">
<link type="text/css" rel="stylesheet" media="screen" href="/Manage/css/debugCss.css">
<link type="text/css" rel="stylesheet" media="screen" href="/Manage/css/css2.css">
<script type="text/javascript">
var dbid = "25,27"; //定义项目标识,区分不同的项目
var dataBaseId = 25;
var projectId = "1,2,3";
</script>
</head>
<body>
<div id="foo"></div> <!—加载动画-->
<div id="div_Show" class="clearfix">
<div id="div_logo">
<span id="showMe"></span>
<span id="webTitle">后台管理 </span>
<span id="exit" onclick="delCookie('saleUserID___')"> 退 出 </span>
</div>
<div style="width:200px;">
<div >导航菜单</div>
<div id="divTree">
<div :key="'tree_' + tree.ModuleID" v-for="tree in trees" v-on:click="treeClick(tree.ModuleID,tree.ModuleName)" v-bind:class="'tree' + tree.ModuleLevel">{{tree.ModuleName}}</div>
</div>
</div>
<div id="div_Main" class="inner">
<ul id="ulTab" class="tabs left">
<li v-for="t in tabs" v-bind:class="{'selectTag':t.isShow}">
<a v-on:click="tabClick(t.id)" href="javascript:void(0)">
{{t.title}} {{t.id==='1'?tabNumber:''}}
<em class="arrup" v-on:click.stop="closeTab(t.id)">x</em>
</a>
</li>
</ul>
<div id="divIframe">
<div v-for="t in tabMains" v-bind:class="{'selectTag':t.isShow}" v-show="t.isShow">
{{ t.message }}
<table class="table_default1" style="" v-show="t.message!=='欢迎使用!'">
<tr>
<th v-for="key in t.orderBy">
{{t.tableTh[key].title}}
</th>
</tr>
<tr v-for="(tr,i) in t.dataList">
<td v-for="index in t.orderBy" v-bind:align="t.tableTh[index].align">
{{tr[index]}}
</td>
</tr>
</table>
<!--分页控件-->
<div id="divQuickPage" v-show="t.message!=='欢迎使用!'">
<div id="quickPage">
<div id="quickPager" class="pagesize1">
<span class="pagetext1" style="cursor: pointer;">共<strong>{{t.pageTurn.recordCount}}</strong>条记录</span>
<span class="pagetext1" style="cursor: pointer;">第<strong>{{t.pageTurn.pageIndex}}</strong>/<strong>{{t.pageTurn.pageCount}}</strong>页</span>
<span class="pagetext1" style="cursor: pointer;">每页<strong>{{t.pageTurn.pageSize}}</strong>条记录</span>
<span id="navi" style="cursor: pointer;">
<a v-for="(p,index) in t.pageTurn.pageCount" v-on:click="naviClick(t.tabId,index+1)">{{index+1}}</a>
</span>
<a id="first" class="disabled">首页</a>
<a id="prev" class="disabled">上一页</a>
<a id="next" v-on:click="naviClick(t.tabId,2)">下一页</a>
<a id="last">末页</a>
<input type="text" id="txtGo" size="3" class="cssTxt">
<a id="spanGo">GO</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div> <div id="div_Copyright">
<span id="divDegub" onclick="DebugShow()">debug</span> <span id="Span1" onclick="DebugCache()">cache</span>
<span id="Span2" onclick="DebugShow()">event</span> by 自然框架之UI Vue + Json + ashx
</div>
</body>
Vue的代码
//树的数据包
var tree = new Vue({
el: '#divTree',
data: {
trees: [
{
IsHidden: 0,
ModuleID: -10,
ModuleLevel: 1,
ModuleName: "系统管理",
ParentID: 0,
ParentIDAll: "0",
Target: "_self",
URL: "#"
}
]
},
methods: {
treeClick: function (id,title) {
//隐藏前一个的tab
var oldId = tab.currentTabId; //记录切换前tab的id
tab.beforeTabId = oldId;
tab.tabs["tab" + oldId].isShow = false; //隐藏切换前的tab
tabDiv.tabMains["tab" + oldId].isShow = false; //隐藏切换前的tab容器
tab.currentTabId = id; //记录新的id
//创建tab
var newTab = {
id: id, //标签识别标示
title: title,
isShow: true, //是否显示
message: title
}; //创建tab 的容器
var main = {
message:title,
isShow: true, //是否显示
tabId: id //标签识别标示
}; if (typeof (tab.tabs["tab" + id]) === "undefined")
tab.tabNumber = tab.tabNumber + 1; Vue.set(tab.tabs, "tab" + id, newTab); if (typeof (tabDiv.tabMains["tab" + id]) === "undefined") {
//没有加载描述,加载表格的描述信息
this.$http.get('/MetaData/GetMeta.ashx?action=grid&mdid=' + id + '&mpvid=' + id + '01&dbid=' + dbid + '&_=1563').then(function (res) {
//创建table
var table = {
message: title,
isShow: true, //是否显示
tabId: id, //标签识别标示
orderBy: [], //可以控制字段的先后顺序,想调整列的先后顺序,改这个数组就行,可以做个性化设置
tableTh: {}, //表头的描述信息
dataList: [] //数据包,字段名作为关键字,便于列的调整先后顺序
}; for (var key in res.body.data) {
var d = res.body.data[key]; table.tableTh["" + d.ColumnID] = {
title: d.ColName,
align: d.ColAlign
};
table.orderBy.push("" + d.ColumnID);
}
Vue.set(tabDiv.tabMains, "tab" + id, table);
//获取数据
getDataList(id); }, function () {
console.log('请求表头失败');
});
} else {
//获取数据
getDataList(id);
} //获取数据
function getDataList(id) {
tabDiv.$http.get('/Data/GetData.ashx?action=list&mdid=' + id + '&mpvid=' + id + '01&fpvid=' + id + '02&frid=-2&frids=-2&pageno=1&pagerc=0&dbid=' + dbid + '&webappid=1&_=' + Date.now()).then(function (res) {
var tableData = tabDiv.tabMains["tab" + id]; tableData.dataList = res.body.data;
tableData.pageTurn = res.body.pageTurn;
tableData.isShow = true; //显示切换前的tab容器 Vue.set(tabDiv.tabMains, "tab" + id, tableData); }, function () {
console.log('请求数据失败');
});
}
}
}
}); //标签的数据包,只有标签,没有标签下面的容器
var tab = new Vue({
el: '#ulTab',
data: {
tabNumber: 1, //标签数量,这个是临时的,便于自动重新绑定
currentTabId: 1, //当前激活的tab的id
beforeTabId: 1, //上一个被激活的tab的id
tabs: {
tab1: { //可以有多个标签,
id: "1", //标签识别标示
title: "我的桌面",
isShow: true, //是否显示
message: '桌面'
}
}
},
methods: {
tabClick: function (id) {
//切换tab
var oldId = tab.currentTabId; //记录切换前tab的id
tab.beforeTabId = oldId;
tab.tabs["tab" + oldId].isShow = false; //隐藏切换前的tab
tabDiv.tabMains["tab" + oldId].isShow = false; //隐藏切换前的tab容器 tab.currentTabId = id; //记录切换后的id
tab.tabs["tab" + id].isShow = true; //显示切换后的tab
tabDiv.tabMains["tab" + id].isShow = true; //显示切换前的tab容器
},
closeTab: function (id) {
if (id === "1") {
alert("这是桌面,建议不要关闭哦:)");
return;
} delete tab.tabs["tab" + id]; //不知道有没有更好的办法
tab.tabNumber = tab.tabNumber - 1; //设置“激活”状态
var oldId = tab.beforeTabId; //上一个激活tab
var nowId = tab.currentTabId; //现在激活tab if (nowId === id) {
//关掉的是激活tab,需要设置上一个tab为激活状态
tab.currentTabId = oldId;
tab.tabs["tab" + oldId].isShow = true;
tab.beforeTabId = 1;
}
else if (oldId === id) {
//关闭的是上一个激活tab,修改前一个tab的id
tab.beforeTabId = 1;
} else {
//需要强制修改一下,否则不会刷新
tab.currentTabId = nowId;
}
}
}
}); //tab下面的容器的数据包
var tabDiv = new Vue({
el: '#divIframe',
data: {
tabMains: {
tab1: { //可以有多个标签,
message: '欢迎使用!',
isShow: true, //是否显示
tabId: "1", //标签识别标示
orderBy: [], //可以控制字段的先后顺序,想调整列的先后顺序,改这个数组就行,可以做个性化设置
tableTh: {}, //表头的描述信息
dataList: [], //数据包,字段名作为关键字,便于列的调整先后顺序
pageTurn: {
//naviCount: 5, //显示页码数量
//pageCount: 3, //总页数
//pageIndex: 1, //当前页数
//pageSize: 20, //一页记录数
//recordCount: 58 //总记录数
}
}
}
},
methods: {
naviClick: function(id,pageIndex) {
tabDiv.$http.get('/Data/GetData.ashx?action=list&mdid=' + id + '&mpvid=' + id + '01&fpvid=' + id + '02&frid=-2&frids=-2&pageno=' + pageIndex + '&pagerc=0&dbid=' + dbid + '&webappid=1&_=' + Date.now()).then(function (res) { var tableData = tabDiv.tabMains["tab" + id];
tableData.dataList = res.body.data;
tableData.pageTurn = res.body.pageTurn; Vue.set(tabDiv.tabMains, "tab" + id, tableData); }, function () {
console.log('请求数据失败');
});
}
}
}); //从后端获取树,然后绑定。以前的项目,现成的接口先拿来用了。
tree.$http.get('/MetaData/GetMeta.ashx?action=tree&mdid=0&dbid=25&ProjectID=1,2,3&cacheKey=0&webappid=1&_=15640190').then(function (res) {
tree.trees = res.body.data; //后端的数据直接赋值,然后就自动绑定上了。
}, function () {
console.log('请求失败处理');
});
总结
1、 因为是初学vue,所以代码还不够规范,有些地方并不是很理想。还有很多需要优化和改进的地方。
2、 关于脚本和工程化。脚本比较简单直接,引用vue.Js就可以开鲁,便于试验自己的想法,而且vue的大部分方法也都是支持脚本方式的,还没学到路由那一块。现在先用脚本的方式来实现,然后在逐步转成工程化的方式。或者保持两种方式共存。这样更灵活吧,反正代码也没多少。
3、 虽然现在代码不多,但是实现的功能类型也不多,只是简单的数据列表,还没加上查询和按钮组,还有更复杂的表单控件。这些功能都加上之后,代码会变得更加的臃肿,也就意味着一步步走向深渊——不可维护、不可扩展。那么怎么办呢?
4、 代码的可维护性——组件化。做成组件的方式来分割代码。Emmmm,不知道vue还有没有更好的方式。总之有好的方法都可以拿来用。
5、 代码的可扩展性,目前tab里面只能放数据列表,还没想到更好的方式放其他类型的内容,以前用了一个粗暴的方式——iframe,想放啥都可以。现在不想用iframe了。
下一步是研究一下表单的问题了。
从后端到前端之Vue(四)小试牛刀——真实项目的应用(树、tab、数据列表和分页)的更多相关文章
- legend2---开发日志6(后端和前端如何相互配合(比如php,js,元素状态和数据改变))
legend2---开发日志6(后端和前端如何相互配合(比如php,js,元素状态和数据改变)) 一.总结 一句话总结:php给元素初始状态,js根据这个状态做初始化和后续变化,使用vue真的很方便( ...
- 从后端到前端之Vue(一)写个表格试试水
目录: 1.脚本式开发. 2.工程化开发 3.工程化和脚本的区别 4.来个table试试水 4,1.目标 4.2.思路 4.3.设计与编码 4.4.效果 5.业务分离 6.功能拓展——个性化设置 ...
- 从后端到前端之Vue(三)小结以及一颗真实的大树
上一篇写了一下tab,下面整理一下用过的知识点,本想按照官网的文档,整理一下可以更清晰,结果也许是我的方法不对吧,总之更模糊了. 按照官网文档的顺序整理到了表单输入绑定之前,因为之前大致也就只涉及到这 ...
- 【前端】Vue.js经典开源项目汇总
Vue.js经典开源项目汇总 原文链接:http://www.cnblogs.com/huyong/p/6517949.html Vue是什么? Vue.js(读音 /vjuː/, 类似于 view) ...
- 从后端到前端之Vue(二)写个tab试试水
上一篇写了一下table,然后要写什么呢?当然是tab了.动态创建一个tab,里面放一个table,这样一个后台管理的基本功能(之一)就出来了. 好吧,这里其实只是试试水,感受一下vue的数据驱动可以 ...
- 从后端到前端之Vue(六)表单组件
表单组件 做项目的时候会遇到一个比较头疼的问题,一个大表单里面有好多控件,一个一个做设置太麻烦,更头疼的是,需求还总在变化,一会多选.一会单选.一会下拉的,变来变去的烦死宝宝了. 那么怎么解决这个问题 ...
- 从后端到前端之Vue(五)小试路由
一开始我还以为vue的路由只能用在工程化的项目里面呢,然后研究了一下才发现,在脚本化里面也是可以用的.其实呢不管在哪里用,把原理研究明白就对了. 一. 官网demo 这里不得不吐槽一下官网,写的不清不 ...
- 循序渐进VUE+Element 前端应用开发(19)--- 后端查询接口和Vue前端的整合
循序渐进VUE+Element 前端应用开发的系列文章中,前面介绍了系统各个功能的处理实现,本篇随笔从一个主线上介绍前后端开发的整合,让我们从ABP框架后端的查询接口的处理,前端API接口调用的封装, ...
- 【前端vue开发架构】vue开发单页项目架构总结
为营销活动设计的前端架构 主要的技术栈为 Vuejs,Webpack,请自行阅读如下技术或者框架的文档: 一.基础说明: node (https://nodejs.org/en/) npm (http ...
随机推荐
- ACM竞赛中的魔方问题专题(不定时更新)
魔方有6个面,有24中不同的旋转方式: 一般有两种方法: (一):以1面为顶面,向右旋转0,90,180,270度 以2面为顶面,向右旋转0,90,180,270度 ... 以6面为顶面,向右旋转0, ...
- Flask学习之旅--数据库
一.写在前面 在Web开发中,数据库操作是很重要的一部分,因为网站的很多重要信息都保存在数据库之中.而Flask在默认情况下是没有数据库.表单验证等功能的,但是可以用Flask-extension为W ...
- SpringCloud-分布式配置中心【加密-对称加密】
前面我们介绍了SpringCloud的分布式配置中心,我们将项目中的配置信息保存在git或者码云的仓库中,但是这样一些敏感信息就暴露出来了,比如数据库连接的账号密码等信息,这时我们最好能够对这些信 ...
- 3023Java_控制语句
控制语句 0.前定义 语句块(有时叫做复合语句),是用花括号扩起的任意数量的简单Java语句. 块确定了局部变量的作用域.块中的程序代码,作为一个整体,是要被一起执行的. 块可以被嵌套在另一个块中,但 ...
- 解决Linux和Windos不同步的问题
两种方式: 一:在windos上进行操作 (1).cmd中输入如下命令 Reg add HKLM\SYSTEM\CurrentControlSet\Control\TimeZone ...
- 视频直播技术之iOS端推流
随着网络基础建设的发展和资费的下降,在这个内容消费升级的时代,文字.图片无法满足人们对视觉的需求,因此视频直播应运而生.承载了实时性Real-Time和交互性的直播云服务是直播覆盖各行各业的新动力.网 ...
- Spring事物管理简介 (转)
一.事物1.什么是事物 事物指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败 2.事物的特性 原子性:事物是一个不可分割的工作单位,事物中的操作要么都发生,要么都不发生 一致性:事物前后数据 ...
- Thread中的start()方法和自己定义的run()方法有什么区别
在讲这个问题之前引入一下多线程的小知识吧 /*/windows系统中的应用程序来做说明 ,例如:扫雷程序,游戏进行的同时,可以同时记录分数,计算时间等. 其实一个应用程序就是一个可执行文件,中包含了一 ...
- Java:synchronized关键字引出的多种锁
前言 Java 中的 synchronized关键字可以在多线程环境下用来作为线程安全的同步锁.本文不讨论 synchronized 的具体使用,而是研究下synchronized底层的锁机制,以及这 ...
- 透视BlueStore存储结构:如何根据文件名从裸盘提取文件内容
在FileStore下,用户文件经过切分对象块后最终存放在了单机文件系统(xfs .ext4等)中,我们可以较容易地找到这些对象块对应的文件,然后提取这些对象块文件后组装成用户文件.然而,BlueSt ...