使用APICloud AVM多端框架开发企业移动OA办公的项目实践
本项目主要是针对企业内部员工使用,除了大部分OA办公常用的功能模块,也有部分定制化的功能模块。后台用的PHP+BootStrap+Easyui(PS:是不是感觉很久远的技术了)。功能介绍1、考勤打卡签到,加班打卡签到2、办公流程申请、审批3、通知下发、短信消息提醒4、个人考勤记录查询,按月统计、钻取查询明细思维导图 技术要点Flex布局,amap地图应用,消息推送,短信提醒。应用模块项目目录开发介绍首页导航系统首页使用tabLayout,可以将相关参数配置在JSON文件中,再在config.xml中将content的值设置成该JSON文件的路径。如果底部导航没有特殊需求这里强烈建议大家使用tabLayout为APP进行布局,官方已经将各类手机屏幕及不同的分辨率进行了适配,免去了很多关于适配方面的问题。{
"name": "root",
"hideNavigationBar": false,
"bgColor": "#fff",
"navigationBar": {
"background": "#1492ff",
"shadow": "rgba(0,0,0,0)",
"color": "#fff",
"fontSize": 18,
"hideBackButton": true
},
"tabBar": {
"background": "#fff",
"shadow": "#eee",
"color": "#5E5E5E",
"selectedColor": "#1492ff",
"textOffset": 3,
"fontSize": 11,
"scrollEnabled": true,
"index": 0,
"preload": 1,
"frames": [{
"name": "home",
"url": "./pages/index/index.stml",
"title": "首页"
}, {
"name": "notice",
"url": "./pages/notice/notice.stml",
"title": "通知"
}, {
"name": "records",
"url": "./pages/records/records.stml",
"title": "记录"
}, {
"name": "user",
"url": "./pages/wode/wode.stml",
"title": "我的"
}],
"list": [{
"text": "首页",
"iconPath": "./images/toolbar/icon-home.png",
"selectedIconPath": "./images/toolbar/icon-home-selected.png"
}, {
"text": "通知",
"iconPath": "./images/toolbar/icon-notice.png",
"selectedIconPath": "./images/toolbar/icon-notice-selected.png"
}, {
"text": "记录",
"iconPath": "./images/toolbar/icon-records.png",
"selectedIconPath": "./images/toolbar/icon-records-selected.png"
}, {
"text": "我的",
"iconPath": "./images/toolbar/icon-user.png",
"selectedIconPath": "./images/toolbar/icon-user-selected.png"
}]
}
}接口调用将接口调用和接口配置分别封装了2个JS插件,model.js和config.js。这样来统一管理,避免了在每个页面进行接口调用的时候都重复写一遍代码,有效的简化了每个功能页面的代码量,只需要在回调里专注写自己的业务逻辑即可。插件引用import {Model} from "../../utils/model.js"
import {Config} from "../../utils/config.js"config.jsclass Config{
constructor(){}
}
Config.restUrl = 'http://127.0.0.1/index.php/Home/Api';
Config.queryrecordsbymonth ='/queryrecordsbymonth';//获取用户本月考勤记录
//省略
export {Config};model.jsimport {Config} from './config.js';
class Model {
constructor() {}
}
/*获取用户本月考勤记录 */
Model.queryrecordsbymonth = function (param, callback){
param.url = Config.queryrecordsbymonth;
param.method = 'post';
this.request(param, callback);
}
/*省略*/
Model.request = function(p, callback) {
var param = p;
if (!param.headers) {
param.headers = {};
}
// param.headers['x-apicloud-mcm-key'] = 'SZRtDyzM6SwWCXpZ';
if (param.data && param.data.body) {
param.headers['Content-Type'] = 'application/json; charset=utf-8';
}
if (param.url) {
param.url = Config.restUrl + param.url;
}
api.ajax(param, function(ret, err) {
callback && callback(ret, err);
});
}
export {Model};页面中调用接口//获取当前用户的本月考勤记录
recordsbymonth() {
const params = {
data:{
values:{
userid: api.getPrefs({sync: true,key: 'userid'}),
secret: Config.secret
}
}
}
Model.queryrecordsbymonth(params, (res,err) => {
console.log(JSON.stringify(res));
console.log(JSON.stringify(err));
if (res && res.flag == "Success") {
this.data.dk = res.data.dk;
this.data.cd = res.data.cd;
this.data.zt = res.data.zt;
this.data.tx = res.data.tx;
this.data.qj = res.data.qj;
}
else{
this.data.dk = 0;
this.data.cd = 0;
this.data.zt = 0;
this.data.tx = 0;
this.data.qj = 0;
}
api.hideProgress();
});
},消息推送消息推动采用了官方的push模块,因为产生消息提醒的事件都是在APP中进行触发,所有就用了官方的push模块;如果存在后台系统操作产生消息提醒的,官方的push模块就不适用了,需要用Jpush等三方消息推送平台模块,配合后台SDK进行消息推送。用户绑定//判断是否绑定推送
if(api.getPrefs({sync: true,key:'pushstatus'})!='02'){
var push = api.require('push');
push.bind({
userName: api.getPrefs({sync: true,key:'name'}),
userId: api.getPrefs({sync: true,key:'id'})
}, function(ret, err){
if( ret ){
// alert( JSON.stringify( ret) );
api.toast({
msg:'推送注册成功!'
});
//设置推送绑定状态,启动的时候判断一下
api.setPrefs({key:'pushstatus',value:'02'});
}else{
// alert( JSON.stringify( err) );
api.toast({
msg:'推送注册失败!'
})
api.setPrefs({key:'pushstatus',value:'01'});
}
});
}推送消息//发送抄送通知
copypush(){
const params = {
data:{
values:{
secret: Config.secret,
content:'有一条早晚加班申请已审批完成!'
}
}
}
Model.createcopytousermessage(params, (res,err) => {
// console.log(JSON.stringify(res));
// console.log(JSON.stringify(err));
if (res && res.flag == "Success") {
var users = res.data.join(',');
var now = Date.now();
var appKey = $sha1.sha1("A61542********" + "UZ" + "6B2246B9-A101-3684-5A34-67546C3545DA" + "UZ" + now) + "." + now;
api.ajax({
url : 'https://p.apicloud.com/api/push/message',
method : "post",
headers: {
"X-APICloud-AppId": "A615429********",
"X-APICloud-AppKey": appKey,
"Content-Type": "application/json"
},
dataType: "json",
data: {
"body": {
"title": "消息提醒",
"content": '有一条早晚加班申请已审批完成!',
"type": 2, //– 消息类型,1:消息 2:通知
"platform": 0, //0:全部平台,1:ios, 2:android
"userIds":users
}
}
}, (ret, err)=> {
// console.log(JSON.stringify(ret))
// console.log(JSON.stringify(err))
});
}
});
}Flex布局flex布局在AVM开发中是重中之重!还是那句话,flex布局写好,有CSS基础,根本就不需要用UI组件,完全可以实现UI的设计稿。关于flex布局推荐一下阮一峰老师的教程,多读几遍多用,自然就会用的得心应手!上链接:https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html通知公告由于通知公告的内容是在后台通过富文本编辑器编辑的内容,其中会有样式布局的元素,不再是单纯的文字展示,这里使用了AVM中的rich-text组件,这个组件能很好的支持一些html元素标签,能完美的把富文本编辑的内容展现出来。<template name='notice_info'>
<scroll-view class="main" scroll-y>
<text class="title">{this.data.title}</text>
<text class="subtitle">{this.data.author}|{this.data.sj}</text>
<rich-text class="content" nodes={this.data.content}></rich-text>
</scroll-view>
</template>数据列表及分页查询数据列表的展示,采用scroll-view标签,通过onrefresherrefresh,onrefresherrefresh出发的事件中进行数据列表的刷新,和分页查询。refresher-triggered这个属性来设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发。如果想默认下拉刷新一下可以在apiready中将之设置为true,以此来代替执行数据刷新操作。如果列表中的每一项的元素较少,而且没有样式的特殊要求,也可以使用list-view来实现。下面是以通知公告列表的完整页面代码。其他页面的列表基本功能都是一致的,只是在每一项的样式及参数个数存在差异。<template>
<scroll-view class="main" scroll-y enable-back-to-top refresher-enabled refresher-triggered={refresherTriggered} onrefresherrefresh={this.onrefresherrefresh} onscrolltolower={this.onscrolltolower}>
<view class="item-box">
<view class="item" data-id={item.id} onclick={this.openNoticeInfo} v-for="(item, index) in noticeList">
<text class="item-content">{{item.title}}</text>
<view class="item-sub">
<text class="item-info">{{item.dt}}</text>
<text class="item-info">{{item.author}}</text>
</view>
</view>
</view>
<view class="footer">
<text class="loadDesc">{loadStateDesc}</text>
</view>
</scroll-view>
</template>
<script>
import {Model} from '../../utils/model.js'
import {Config} from "../../utils/config.js"
import $util from "../../utils/util.js"
export default {
name: 'notice',
data() {
return{
noticeList: [],
skip: 0,
loading: false,
refresherTriggered: false,
haveMoreData: true
}
},
computed: {
loadStateDesc(){
if (this.data.loading || this.data.haveMoreData) {
return '加载中...';
} else if (this.noticeList.length > 0) {
return '没有更多啦';
} else {
return '暂时没有内容';
}
}
},
methods: {
apiready(){
this.data.refresherTriggered = true;
this.loadData(false);
},
loadData(loadMore) {
this.data.loading = true;
var that = this;
var limit = 20;
var skip = loadMore?that.data.skip+1:0;
let params = {
data:{
values:{
secret: Config.secret,
userid: api.getPrefs({sync: true,key: 'userid'}),
skip: skip,
limit: limit
}
}
}
Model.getNoticeList(params, (res) => {
if (res && res.flag == 'Success') {
let notices = res.data;
that.data.haveMoreData = notices.length == limit;
if (loadMore) {
that.data.noticeList = that.data.noticeList.concat(notices);
} else {
that.data.noticeList = notices;
}
that.data.skip = skip;
} else {
that.data.haveMoreData = false;
}
that.data.loading = false;
that.data.refresherTriggered = false;
});
},
//打开通知详情页
openNoticeInfo: function (e) {
var id = e.currentTarget.dataset.id;
$util.openWin({
name: 'notice_info',
url: '../notice/notice_info.stml',
title: '通知详情',
pageParam:{
id:id
}
});
},
/*下拉刷新页面*/
onrefresherrefresh(){
this.data.refresherTriggered = true;
this.loadData(false);
},
onscrolltolower() {
if (this.data.haveMoreData) {
this.loadData(true);
}
}
}
}
</script>
<style>
.main {
height: 100%;
background-color: #f0f0f0;
}
.item-box{
background-color: #fff;
margin: 5px 5px;
}
.item{
border-bottom: 1px solid #efefef;
margin: 0 10px;
justify-content:flex-start;
flex-direction:column;
}
.item-content{
font-size: 17PX;
margin-top: 10px;
}
.item-info{
font-size: 13PX;
color: #666;
margin: 10px 0;
}
.item-sub{
justify-content:space-between;
flex-direction:row;
}
.footer {
height: 44px;
justify-content: center;
align-items: center;
}
.loadDesc {
width: 200px;
text-align: center;
}
</style>组件开发此项目中将模块缺省页和无数据页面封装为组件,方便在有数据查询的页面,不存在数据的情况直接引用组件即可。在事件项目需求中,尽量将通用的代码模块,封装成组件,这样不仅简化了页面代码量,而且很方便维护项目,组件中的内容修改一次,就可以应用到很多的使用组件的页面。具体的开发教程可参考官方给出的教程并结合官方给出的点餐模板中的教程进行编写。这是官方链接:https://docs.apicloud.com/APICloud/Order-template-description需要注意的点是,组件中使用installed,页面中使用apiready,如果组件中使用了apiready不会报错,但是不会执行你想要的结果。地图模块使用本应用中使用的是搞得地图amap,具体使用教程可通过模块使用教程进行详细了解,amp模块包含的功能特别丰富,基本上可以满足99%的关于地图的需求。下面主要说明几点在使用高德地图过程中踩过的坑:1、由于高德地图是原生模块,如果一个页面中地图只是其中一部分的元素的话,就需要注意地图的大小及位置,因为原生模块会遮罩页面元素,所以在固定好地图元素的位置之后,页面中的其他元素也要进行调整,我是用一个空白的view元素来占用地图组件的位置,然后在去调整其他页面的元素。2、由于本项目中的考勤打卡是根据打卡位置进行了是否外勤的判断,正好用到了isCircleContainsPoint这个方法,但是需要注意的是,此方法只有在调用了open接口之后才有效,因为一开始就是做了一个根据经纬度查找地址信息,用到的getNameFromCoords不需要调用open接口即可。就没有调用open接口,导致后来用isCircleContainsPoint这个接口一直是无效的,都快整郁闷了!3、新版本的高德地图应工信部要求,自本模块1.6.0版本起首次调用本模块前必须先弹出隐私协议,详情参考SDK合规使用方案。之后需先调用 updateMapViewPrivacy,updateSearchPrivacy,否则地图和搜索接口都无效。如果你的项目之前用的是老版本的amap,后来打包的时候升级成最新的了,一定要加上这个两个接口! var aMap = api.require('aMap');
aMap.open({
rect: {
x: 0,
y: 80,
h: api.frameHeight-300
},
showUserLocation: true,
showsAccuracyRing:true,
zoomLevel: 13,
center: {
lon: api.getPrefs({sync: true,key: 'lon'}),
lat: api.getPrefs({sync: true,key: 'lat'})
},
fixedOn: api.frameName,
fixed: true
}, (ret, err) => {
// console.log(JSON.stringify(ret));
// console.log(JSON.stringify(err));
if (ret.status) {
//获取用户位置 并判断是否在范围内500米
aMap.getLocation((ret, err) => {
if (ret.status) {
this.data.lon_now = ret.lon;
this.data.lat_now = ret.lat;
//解析当前地理位置
aMap.getNameFromCoords({
lon: ret.lon,
lat: ret.lat
}, (ret, err) => {
// console.log(JSON.stringify(ret));
if (ret.status) {
this.data.address=ret.address;
this.data.province = ret.state;
} else {
api.toast({
msg:'解析当前地理位置失败'
})
}
});
aMap.isCircleContainsPoint({
point: {
lon: api.getPrefs({sync: true,key: 'lon'}),
lat: api.getPrefs({sync: true,key: 'lat'})
},
circle: {
center: {
lon: ret.lon,
lat: ret.lat
},
radius: this.data.distance
}
}, (ret) => {
// console.log(JSON.stringify(ret));
if(ret.status){
this.data.isout=false;
this.data.btn_title='打卡签到';
}
else{
this.data.btn_title='外勤签到';
this.data.isout=true;
api.toast({
msg:'您不在考勤范围内'
})
}
});
} else {
api.toast({
msg:'定位失败,无法签到'
})
}
});
} else {
api.toast({
msg:'加载地图失败'
})
}
});拍照及选择照片因为项目考勤打卡需要每人每天拍3张照片,而且目前手机的像素较高,导致照片体积过大,严重消耗服务器内存;所以拍照使用的是FNPhotograph模块,自带UI的open接口,可选择拍照照片的质量,可配置使用摄像头方向,同时可配置照片不用存储到相册中,禁用显示相册按钮,保证用户只能现场拍照,可以满足项目需求。openCamera (){
var FNPhotograph= api.require('FNPhotograph');
FNPhotograph.openCameraView({
rect: {
x: 0,
y: 80,
w: api.frameWidth,
h: api.frameHeight-70
},
orientation: 'portrait',
fixedOn: api.frameName,
useFrontCamera:true,//使用前置摄像头
fixed: true
}, (ret) => {
// console.log(JSON.stringify(ret));
if(ret.status){
this.data.istakephoto = true;
}
});
},
takephoto (){
var FNPhotograph= api.require('FNPhotograph');
FNPhotograph.takePhoto({
quality: 'low',
qualityValue:30,
path: 'fs://imagepath',
album: false
}, (ret) => {
// console.log(JSON.stringify(ret));
this.data.src = ret.imagePath;
FNPhotograph.closeCameraView((ret) => {
// console.log(JSON.stringify(ret));
if (ret.status) {
this.data.istakephoto = false;
this.data.isphoto = true;
}
});
});
},
showPicture (){
var photoBrowser = api.require('photoBrowser');
photoBrowser.open({
images: [
this.data.src
],
placeholderImg: 'widget://res/img/apicloud.png',
bgColor: '#000'
}, (ret, err) => {
if (ret) {
if(ret.eventType=='click'){
photoBrowser.close();
}
} else {
api.toast({
msg:'图片预览失败'
})
}
});
},关于用户头像的设置,用户可选择拍照和从相册中选择照片。同时支持裁剪以满足用户头像设置的需求。裁剪用到的是FNImageClip模块。在使用FNImageClip模块的时候建议新开frame页面,在新的frame页面进行裁剪操作,裁剪完成之后通过推送事件监听来更新头像!setavator(){
api.actionSheet({
cancelTitle: '取消',
buttons: ['拍照', '打开相册']
}, function(ret, err) {
if (ret.buttonIndex == 3) {
return false;
}
var sourceType = (ret.buttonIndex == 1) ? 'camera' : 'album';
api.getPicture({
sourceType: sourceType,
allowEdit: true,
quality: 20,
destinationType:'url',
targetWidth: 500,
targetHeight: 500
}, (ret, err) => {
if (ret && ret.data) {
$util.openWin({
name: 'facemake',
url: '../wode/facemake.stml',
title: '头像裁剪',
pageParam: {
faceimg:ret.data
}
});
}
});
});
}<template name='facemake'>
<view class="page">
<view class="flowbottom">
<!-- <button class="btn-out" tapmode onclick="closeclip">取消</button>
<button class="btn" tapmode onclick="saveclip">确定</button>
<button class="btn-off" tapmode onclick="resetclip">重置</button> -->
<text class="btn-out" tapmode onclick="closeclip">取消</text>
<text class="btn" tapmode onclick="saveclip">确定</text>
<text class="btn-off" tapmode onclick="resetclip">重置</text>
</view>
</view>
</template>
<script>
import {Model} from "../../utils/model.js"
import {Config} from "../../utils/config.js"
export default {
name: 'facemake',
data() {
return{
facepic:'',
src:''
}
},
methods: {
apiready(){//like created
//取得图片地址
this.data.facepic=api.pageParam.faceimg;
FNImageClip = api.require('FNImageClip');
FNImageClip.open({
rect: {
x: 0,
y: 0,
w: api.winWidth,
h: api.winHeight-75
},
srcPath: this.data.facepic,
style: {
mask: '#999',
clip: {
w: 200,
h: 200,
x: (api.frameWidth-200)/2,
y: (api.frameHeight-275)/2,
borderColor: '#fff',
borderWidth: 1,
appearance: 'rectangle'
}
},
fixedOn: api.frameName
}, (ret, err) =>{
// console.log(JSON.stringify(ret));
// console.log(JSON.stringify(err));
});
},
closeclip(){
FNImageClip = api.require('FNImageClip');
FNImageClip.close();
api.closeWin();
},
saveclip(){
FNImageClip = api.require('FNImageClip');
FNImageClip.save({
destPath: 'fs://imageClip/result.png',
copyToAlbum: true,
quality: 1
},(ret, err)=>{
// console.log(JSON.stringify(ret));
// console.log(JSON.stringify(err));
this.data.src = ret.destPath;
if(ret) {
api.showProgress();
const params = {
data:{
values:{
userid: api.getPrefs({sync: true,key: 'userid'}),
secret: Config.secret
},
files: {'file':[this.data.src]}
}
}
Model.updateuseravator(params, (res,err) => {
// console.log(JSON.stringify(res));
// console.log(JSON.stringify(err));
if (res && res.flag == "Success") {
//广播完善头像事件
api.sendEvent({
name: 'setavator',
extra: {
key: res.data
}
});
api.setPrefs({key:'avator',value:res.data});
api.closeWin();
}
else{
api.toast({
msg:'网络错误,请稍后重试!'
})
}
api.hideProgress();
});
} else{
api.toast({
msg:'网络错误,请稍后重试!'
})
}
});
},
resetclip(){
FNImageClip = api.require('FNImageClip');
FNImageClip.reset();
}
}
}
</script>
<style>
.page {
display: flex;
flex-flow: row nowrap;
height: 100%;
width: 100%;
}
.flowbottom{
width: 100%;
align-self: flex-end;
padding: 10px;
flex-flow: row nowrap;
justify-content: space-around;
}
.btn {
display: block;
height: 30px;
background:#1492ff;
border-radius: 5px;
color: #fff;
font-size: 16px;
padding: 5px 20px;
}
.btn-out {
display: block;
height: 30px;
background:#666;
border-radius: 5px;
color: #fff;
font-size: 16px;
padding: 5px 20px;
}
.btn-off {
display: block;
height: 30px;
background:#ec7d15;
border-radius: 5px;
color: #fff;
font-size: 16px;
padding: 5px 20px;
}
</style>图片预览项目中很多页面涉及到图片预览的功能,分为单图预览和多图预览。图片预览采用的是photoBrowser 模块。photoBrowser 是一个图片浏览器,支持单张、多张图片查看的功能,可放大缩小图片,支持本地和网络图片资源。若是网络图片资源则会被缓存到本地,缓存到本地上的资源可以通过 clearCache 接口手动清除。同时本模块支持横竖屏显示,在本app支持横竖屏的情况下,本模块底层会自动监听当前设备的位置状态,自动适配横竖屏以展示图片。使用此模块开发者看实现炫酷的图片浏览器。<view class="item-bottom" v-if="item.accessory">
<view v-for="p in item.accessory.split(',')" data-url={item.accessory} @click="showPicture">
<image class="item-bottom-pic" :src="this.data.fileaddr+p" mode="aspectFill"></image>
</view>
</view>//查看大图
showPicture(e){
let url = e.currentTarget.dataset.url;
var urlarr= url.split(',');
var images=[];
urlarr.forEach(item => {
images.push(this.data.fileaddr+item);
});
// console.log(JSON.stringify(images));
var photoBrowser = api.require('photoBrowser');
photoBrowser.open({
images: images,
bgColor: '#000'
}, function(ret, err) {
if(ret.eventType=='click'){
photoBrowser.close();
}
});
}清除缓存由于项目中有很多拍照,查看照片,在使用的过程中,就会产生很多的缓存,缓存多了会导致应用反应变慢。所以在应用中增加了清楚缓存的功能,用的是官方提供的api.clearCache。在个人中心 apiready中先获取到应用中的缓存,然后点击清除缓存按钮即可清除。<view class="card_title" onclick="clearCache">
<image class="card_icon" src="../../images/icon/W_17.png" mode="scaleToFill"></image>
<text class="card_item">缓存</text>
<text class="card_right_1">{cache}M</text>
</view>clearCache(){
api.clearCache(() => {
api.toast({
msg: '清除完成'
});
});
this.data.cache=0;
},注册页面、发送手机验证码核心代码在 如何在发送验证码成功之后,设置再次发动验证码倒计时读秒及禁用点击事件。<template name='register'>
<view class="page">
<view class="blank">
<image class="header" src="../../images/back/b_01.png" mode="scaleToFill"></image>
</view>
<view class="item-box">
<input class="item-input" placeholder="请输入11位手机号码" keyboard-type="tel" oninput="getPhone"/>
</view>
<view class="verification-code">
<input class="code-input" placeholder="输入验证码" keyboard-type="number" oninput="getCode"/>
<text v-show={this.data.show} class="code-btn" @click={this.sendCode}>获取验证码</text>
<text v-show={!this.data.show} class="code-btn">{this.data.count}s</text>
</view>
<view class="item-box">
<input class="item-input" placeholder="输入密码(6-20位字符)" type="password" oninput="getPassword"/>
</view>
<view class="item-box">
<input class="item-input" placeholder="确认密码(6-20位字符)" type="password" oninput="getPasswordAgain"/>
</view>
<view class="item-box">
<button class="btn" tapmode onclick="toresigter">注册</button>
</view>
</view>
</template>
<script>
import {Model} from "../../utils/model.js"
import {Config} from "../../utils/config.js"
import $util from "../../utils/util.js"
export default {
name: 'register',
data() {
return{
show:true,
count: '',
timer: null,
phone:'',
code:'',
password:'',
passwordagain:''
}
},
methods: {
apiready(){//like created
},
getPhone(e){
this.data.phone=e.detail.value;
},
getCode(e){
this.data.code=e.detail.value;
},
getPassword(e){
this.data.password=e.detail.value;
},
getPasswordAgain(e){
this.data.passwordagain=e.detail.value;
},
sendCode(){
if(this.data.phone==''||this.data.phone.length !=11){
api.toast({
msg:'请填写正确的手机号!'
})
return false;
}
const TIME_COUNT = 120;
if (!this.timer) {
this.count = TIME_COUNT;
this.show = false;
this.timer = setInterval(() => {
if (this.count > 0 && this.count <= TIME_COUNT) {
this.count--;
} else {
this.show = true;
clearInterval(this.timer);
this.timer = null;
}
}, 1000)
}
//后台发送验证码
api.showProgress();
const params = {
data:{
values:{
phone: this.data.phone,
secret: Config.secret
}
}
}
Model.sendphonecode(params, (res,err) => {
// console.log(JSON.stringify(res));
// console.log(JSON.stringify(err));
if (res && res.flag == "Success") {
api.toast({
msg:'已发送,请注意查收'
})
}
else{
api.toast({
msg:res.msg
});
}
api.hideProgress();
});
},
toresigter(){
if(this.data.phone=='' || this.data.phone.length !=11){
api.toast({
msg:'请填写正确的11位手机号!'
})
return false;
}
if(this.data.code==''){
api.toast({
msg:'请填写验证码!'
})
return false;
}
if(this.data.password==''){
api.toast({
msg:'请填写新密码!'
})
return false;
}
else{
if(this.data.passwordagain==''){
api.toast({
msg:'请填写确认密码!'
})
return false;
}
else if(this.data.passwordagain != this.data.password){
api.toast({
msg:'密码不一致!'
})
return false;
}
}
api.showProgress();
const params = {
data:{
values:{
secret: Config.secret,
phone:this.data.phone,
pwd:this.data.password,
code:this.data.code
}
}
}
Model.resigeruser(params, (res,err) => {
// console.log(JSON.stringify(res));
// console.log(JSON.stringify(err));
if (res && res.flag == "Success") {
api.alert({
title: '提醒',
msg: '注册成功,即将跳转登陆',
}, function(ret, err) {
api.closeWin();
});
}
else{
api.toast({
msg:res.msg
});
}
api.hideProgress();
});
}
}
}
</script>
<style>
.page {
height: 100%;
width: 100%;
flex-flow: column;
justify-content: flex-start;
}
.blank{
height: 300px;
margin-bottom: 50px;
}
.header{
height: 300px;
width: 100%;
}
.item-box{
margin: 10px 20px;
border-bottom: 1px solid #f0f0f0;
}
.item-input{
height: 40px;
width: 100%;
border-radius: 5px;
border: none;
}
.verification-code{
flex-flow: row;
margin: 10px 20px;
justify-content: space-between;
border-bottom: 1px solid #f0f0f0;
}
.code-input{
height: 40px;
width: 70%;
border-radius: 5px;
border: none;
}
.code-btn{
height: 40px;
color: #1492ff;
}
.btn{
display: block;
width: 100%;
height: 50px;
background:#1492ff;
border-radius: 5px;
color: #fff;
font-size: 20px;
font-weight: bolder;
padding: 0;
margin-top: 10px;
}
</style>后台系统登陆接口、注册接口、发送手机验证码、列表查询接口,其中手机短信用的是阿里的短信。阿里短信的SDK通过 composer安装,在需要调用的php文件中头部引用即可。<?php
namespace Home\Controller;
require 'vendor/autoload.php'; // 注意位置一定要在 引入ThinkPHP入口文件 之前
use Think\Controller;
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
class ApiController extends Controller {
//用户登录
public function login(){
checkscret('secret');//验证授权码
checkdataPost('phone');//手机号
checkdataPost('password');//密码
$map['phone']=$_POST['phone'];
$map['password']=$_POST['password'];
$map['ischeck']='T';
$releaseInfo=M()->table('user')
->field('id,name,phone,role,part as partid,user_num as usernum,usercenter,avator')->where($map)->find();
if($releaseInfo){
returnApiSuccess('登录成功',$releaseInfo);
}
else{
returnApiError( '登录失败,请稍后再试');
exit();
}
}
//用户注册
public function resigeruser(){
checkscret('secret');//验证授权码
checkdataPost('phone');//手机号
checkdataPost('password');//密码
checkdataPost('code');//验证码
$phone=$_POST['phone'];
$password=$_POST['password'];
$code=$_POST['code'];
//后台再次验证手机号码有效性
$ckphone=checkphone($phone);
if($ckphone=='T'){
$code_s=S($phone);
if($code_s==$code_s_s){
$data['phone']=$phone;
$data['password']=$password;
$data['role']='01';//注册用户
$data['resiger_time']=time();
$releaseInfo=M()->table('user')->data($data)->add();
if($releaseInfo){
//注销session
S($phone,'');
returnApiSuccess('注册成功',$releaseInfo);
}
else{
returnApiError( '注册失败,请稍后再试');
exit();
}
}
else{
returnApiError('验证码已失效,请重新获取');
exit();
}
}
else{
returnApiError('手机号已注册!');
exit();
}
}
//手机发送验证码
public function sendphonecode(){
checkscret('secret');//验证授权码
checkdataPost('phone');//手机号
$phone=trim($_POST['phone']);
$ckphone=checkphone($phone);
if($ckphone=='T'){//尚未注册手机号
//生成6位验证码
$code = substr(base_convert(md5(uniqid(md5(microtime(true)),true)), 16, 10), 0, 6);
//发送验证码
AlibabaCloud::accessKeyClient(C('accessKeyId'), C('accessSecret'))
->regionId('cn-beijing')
->asDefaultClient();
try {
$param = array("code"=>$code);
$result = AlibabaCloud::rpc()
->product('Dysmsapi')
// ->scheme('https') // https | http
->version('2022-01-25')
->action('SendSms')
->method('POST')
->host('dysmsapi.aliyuncs.com')
->options([
'query' => [
'RegionId' => "cn-beijing",
'PhoneNumbers' => $phone,
'SignName' => "*******有限公司",
'TemplateCode' => "SMS_*******",
'TemplateParam' => json_encode($param),
],
])
->request();
if($result['Code'] == 'OK'){
S($phone,$code,120);//设置一个120秒的过期时间
returnApiSuccess('发送成功',$result);
}
else{
returnApiError( '发送失败,请稍后再试');
exit();
}
} catch (ClientException $e) {
returnApiError( '发送失败,请稍后再试');
exit();
}
}
else{
returnApiError('手机号已注册!');
exit();
}
}
//查询用户加班记录
public function queryovertime(){
checkscret('secret');//验证授权码
checkdataPost('userid');//ID
checkdataPost('limit');//下一次加载多少条
$userid=$_POST['userid'];
//分页需要的参数
$limit=$_POST['limit'];
$skip=$_POST['skip'];
if(empty($skip)){
$skip=0;
}
//查询条件
$map['userid']=$userid;
$releaseInfo=M()->table('overtime_records')->field('id,kssj,ksrq,jsrq,ksbz,jsbz,jssj,kswz,jswz,kszp,jszp,zgsp,jlsp,xzsp,zgsp_time,jlsp_time')->where($map)->limit($limit*$skip,$limit)->order('kssj desc')->select();
if($releaseInfo){
returnApiSuccess('查询成功',$releaseInfo);
}
else{
returnApiSuccess('查询成功',[]);
exit();
}
}
}后台系统页面关于easyui和bootstrap的引用<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>示例</title>
<!-- jquery - boot -库文件 -->
<script src="__PUBLIC__/script/jquery.1.11.1.js"></script>
<script src="__PUBLIC__/script/bootstrap.min.js"></script>
<!-- Bootstrap -->
<link href="__PUBLIC__/css/bootstrap.min.css" rel="stylesheet">
<!-- Bootstrap -->
<!--easyui包含文件-->
<link rel="stylesheet" type="text/css" href="__PUBLIC__/plugins/easyui1.5.3/themes/material/easyui.css">
<link rel="stylesheet" type="text/css" href="__PUBLIC__/plugins/easyui1.5.3/themes/icon.css">
<script type="text/javascript" src="__PUBLIC__/plugins/easyui1.5.3/jquery.easyui.min.js"></script>
<script type="text/javascript" src="__PUBLIC__/plugins/easyui1.5.3/locale/easyui-lang-zh_CN.js"></script>
<!-- end easyui -->
<!--layer-->
<script type="text/javascript" src="__PUBLIC__/plugins/layer/layer.js"></script>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="__PUBLIC__/script/html5shiv.js"></script>
<script src="__PUBLIC__/script/respond.js"></script>
<![endif]-->
</head>主要用到了bootstrap的栅格布局,作为页面布局的使用。eaysui用的是1.5.3版本,用到了下图中的这些控件。具体使用说明可以下载一个chm API使用手册。html页面<div class="container-fluid">
<div class="row">
<div class="col-md-12 mainbox" id="mainbox">
<!--menubegin-->
<div class="datamenubox" id="leftmenu">
<div class="menuhead">****</div>
<!-- treein -->
<div class="treein" id="menuin">
<ul class="list-group smenu">
<volist name="menulist" id="vo">
<a href="{:U($vo[url])}"><li class="list-group-item" id="{$vo.url}"><i class="fa fa-angle-right"></i>{$vo.name}</li></a>
</volist>
</ul>
</div>
</div>
<!--menuend-->
<!--mainboxbegin-->
<div class="col-md-12 rights" id="right">
<!-- 筛选 -->
<div class="searchitem">
<div class="row">
<div class="col-md-12">
<input class="easyui-combobox" name="q_user" id="q_user" style="width:200px" data-options="label:'登记人:',valueField:'id',textField:'text',panelHeight:'180'">
<input class="easyui-textbox" name="q_cphm" id="q_cphm" style="width:200px" data-options="label:'车牌号码:'">
<input class="easyui-datebox" name="q_ksrq" id="q_ksrq" style="width:200px" data-options="label:'开始日期:'">
<input class="easyui-datebox" name="q_jsrq" id="q_jsrq" style="width:200px" data-options="label:'结束日期:'">
</div>
</div>
<div class="blank10"></div>
<div class="row">
<div class="col-md-12">
<div class="btnin" id="normal">
<button class="btn btn-danger" id="querybtn">查询</button>
<button class="btn btn-success" id="exportbtn">导出Excel</button>
<button class="btn btn-info" id="delbtn">删除</button>
</div>
<div class="btnin" id="super">
<button class="btn btn-danger" id="querybtn">查询</button>
<button class="btn btn-success" id="exportbtn">导出Excel</button>
<button class="btn btn-info" id="delbtn">删除</button>
<button class="btn btn-info" id="checkbtn">审核</button>
</div>
</div>
</div>
<!-- end 筛选 -->
</div>
<!-- listtable -->
<div>
<!-- gridview row -->
<table id="dg"></table>
<!-- end gridview row -->
</div>
<!--mainboxend-->
</div>
</div>
</div>
<!-- indexmain end -->
</div>js部分<script>
$(document).ready(function() {
//初始化页面
loaddg();
//用户列表
LoadDDL('q_user','USER');
});
//加载数据列表
function loaddg() {
$('#dg').datagrid({
loadMsg: '正在查询,请稍后...',
title: '',
height: $(window).height() - 300,
url: '{:U(\'queryvehiclefixed\')}',
queryParams: {
user: $('#q_user').combobox('getValue'),
cphm: $('#q_cphm').textbox('getValue'),
ksrq: $('#q_ksrq').datebox('getValue'),
jsrq: $('#q_jsrq').datebox('getValue')
},
nowrap: false,
striped: true,
collapsible: false,
loadMsg: '正在加载,请稍后。。。',
remoteSort: false,
singleSelect: true,
pageSize: 100,
idField: 'id',
pagination: true,
rownumbers: true,
pagination: true,
pageNumber: 1,
pageSize: 20,
pageList: [20, 40, 80, 160],
fitColumns: true,
columns: [
[{
field: 'cphm',
title: '车牌号码',
width: 50
}, {
field: 'date',
title: '申请时间',
width: 70
}, {
field: 'user',
title: '申请人',
width: 70
}, {
field: 'part',
title: '所属部门',
width: 70
}, {
field: 'description',
title: '问题描述',
width: 100
}, {
field: 'mileage',
title: '公里数',
width: 50
}, {
field: 'zgsp',
title: '主管审批',
width: 50,
styler: function(value,row,index){
if (value =='同意'){
return 'color:green;';
}
else if(value == '拒绝'){
return 'color:red;';
}
}
}]
]
});
$("#querybtn").click(function() {
$('#dg').datagrid('load', {
"user": $('#q_user').combobox('getValue'),
"cphm": $('#q_cphm').textbox('getValue'),
"ksrq": $('#q_ksrq').datebox('getValue'),
"jsrq": $('#q_jsrq').datebox('getValue')
});
});
}
//删除
$('#delbtn').click(function(){
var row = $('#dg').datagrid('getSelected');
if(row){
layer.confirm('您确定要删除选中的数据?', {
btn: ['是','否'] //按钮
}, function(){
var option = {
type: "POST",
url: "{:U('delvehiclefixed')}",
data: {id:row.id},
success: function (data) {
layer.closeAll();
layer.msg(data);
$('#dg').datagrid('reload');
}
};
$.ajax(option);
}, function(){
layer.closeAll();
});
}
else{
layer.msg('请选择需要删除的数据!');
}
})
//审核
$('#checkbtn').click(function(){
var row = $('#dg').datagrid('getSelected');
if(row){
layer.confirm('请对此条申请做出审核', {
btn: ['同意','不同意'] //按钮
}, function(){
var option = {
type: "POST",
url: "{:U('checkvehiclefixed')}",
data: {id:row.id,ret:'02'},
success: function (data) {
layer.closeAll();
layer.msg(data);
$('#dg').datagrid('reload');
}
};
$.ajax(option);
}, function(){
var option = {
type: "POST",
url: "{:U('checkvehiclefixed')}",
data: {id:row.id,ret:'03'},
success: function (data) {
layer.closeAll();
layer.msg(data);
$('#dg').datagrid('reload');
}
};
$.ajax(option);
});
}
else{
layer.msg('请选择需要审核的数据!');
}
})
</script>
基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用
在前面介绍了两篇关于我的基于MVC4+EasyUI技术的Web开发框架的随笔,本篇继续介绍其中界面部分的一些使用知识,包括控件的赋值、取值、清空,以及相关的使用。
我们知道,一般Web界面包括的界面控件有:单行文本框、多行文本框、密码文本框、下拉列表Combobox、日期输入控件、数值输入控件、单项选择、复选框、表格控件DataGrid、树形控件、布局控件、弹出式对话框、提示信息、列表控件等,这些界面控件的操作都有哪些不同,下面我们来逐一进行介绍。
1、单行文本框
使用easyui的控件,单行文本可以使用easyui-validatebox样式即可,类型为text的控件。
界面代码如下所示:
<input class="easyui-validatebox" type="text" id="Name" name="Name" />
或者
<input type="text" ID="txtLoginName" name="txtLoginName" style="width:100px" />
赋值给界面控件代码如下:
$("#Name").val(info.Name);
获取界面控件的值代码如下:
var name = $("#Name").val();
如果是标签Lable控件,这需要把val 使用text替代即可,如下代码所示:
$("#Name").text(info.Name);
对于easyui-validatebox样式的控件,一般来说,有几个常见属性可以设置他们的。
//必输项:
<input class="easyui-validatebox" type="text" name="name" data-options="required:true"></input>
//格式的验证:
<input class="easyui-validatebox" type="text" name="email" data-options="validType:'email'"></input>
<input class="easyui-validatebox" type="text" name="email" data-options="required:true,validType:'url'"></input>
//长度范围的验证:
<input class="easyui-validatebox" data-options="validType:'length[1,3]'">
2、多行文本框
easyui的界面样式,可以使用easyui-validatebox,或者默认的textarea即可。
界面代码如下所示:
<textarea id="type_Remark" class="easyui-validatebox" required="true" style="height:100px;"></textarea>
或者
<textarea style="height:60px;width:200px" id="type_Remark" name="Remark"></textarea>
赋值给界面控件代码如下:
$("#type_Remark").val(json.Remark);
获取界面控件的值代码如下:
var text = $("#type_Remark").val();
3、密码文本框
密码文本框和常规的文本框一样,只是输入字符的时候,系统做了屏蔽显示而已,把它作为一个来独立说明,也是因为它也是常见输入的一种。
界面代码如下所示:
<input type="password" name="password" style="width:260px;"></input>
赋值给界面控件代码如下:
var password = '123';
$("#Password").val(password)
获取界面控件的值代码如下:
$("#btnLogin").click(function () {
var postData = {
UserName: $("#UserName").val(),
Password: $("#Password").val(),
Code: $("#Code").val()
};
4、下拉列表Combobox
常见的EasyUI的ComboBox是可以输入,也可以从列表选择的内容的输入控件。
界面代码如下所示:
<input class="easyui-combobox" type="text" id="type_PID1" name="PID" />
绑定下拉列表的数据源代码如下:
$('#type_PID1').combobox({
url: '/DictType/GetDictJson',
valueField: 'Value',
textField: 'Text'
});
设置控件的选择的内容代码如下:
$("#type_PID1").combobox('setValue', json.PID);
获取界面控件的值代码如下:
var systemType= $("#txtSystemType_ID").combobox('getValue');
而利用标准的Select控件虽然可以实现从列表选择,不过不够ComboBox控件那么灵活方便,Select控件的界面代码如下:
<select id="txtPID" style="width: 100%" > </select>
5、日期输入控件
easyui使用class=‘easyui-datebox’来标识日期控件,从弹出的层中选择正确的日期,是一种非常常见的界面输入控件,可以替代My97DatePicker日期输入控件。
弹出窗体界面效果如下。
它的界面代码如下所示:
<input class="easyui-datebox" type="text" ID="txtLastUpdated" name="txtLastUpdated" style="width:100px" />
赋值给界面控件代码如下:
$("#LastUpdated").datebox('setValue', info.LastUpdated);
获取界面控件的值代码如下:
var lastupate = $("#txtLastUpdated").datebox('getValue');
6、数值输入控件
easyui使用样式easyui-numberbox标识为数值类型,其表现为文本框,但只能输入数值。
界面代码如下所示:
<input class="easyui-numberbox" data-options="min:10,max:90,precision:2,required:true">
或者使用‘easyui-numberspinner’样式来标识,可以上下调节数值。
<input class="easyui-numberspinner" data-options="min:10,max:100,required:true" style="width:80px;"></input>
赋值给界面控件代码如下:
$('#nn').numberbox('setValue', 206.12);
或者
$('#ss').numberspinner('setValue', 8234725);
获取界面控件的值代码如下:
var v = $('#nn').numberbox('getValue');
或者
var v = $('#ss').numberspinner('getValue');
7、单项选择Radio控件
单项选择Radio控件,是在多项内容里面选择一个选项进行保存或者显示。
界面代码如下所示:
<tr>
<th>
<label>数据分开方式:</label>
</th>
<td>
<input name="SplitType" type="radio" class="easyui-validatebox" checked="checked" required="true" value="Split">分隔符方式,多个数据中英文逗号,分号,斜杠或顿号[, , ; ; / 、]分开,或一行一个
<br />
<input name="SplitType" type="radio" class="easyui-validatebox" required="true" value="Line">一行一个记录模式,忽略所有分隔符号
</td>
</tr>
赋值给界面控件代码如下:
$('input:radio[name="SplitType"][value="Split"]').prop('checked', true);
获取界面控件的值代码如下:
$("input[name='SplitType']:checked").val()
或者使用Comobo控件作为单项选择的控件也是可以的,界面效果如下所示。
其界面代码如下所示:
<select id="cc" style="width:150px"></select>
<div id="sp">
<div style="color:#99BBE8;background:#fafafa;padding:5px;">Select a language</div>
<input type="radio" name="lang" value="01"><span>Java</span><br/>
<input type="radio" name="lang" value="02"><span>C#</span><br/>
<input type="radio" name="lang" value="03"><span>Ruby</span><br/>
<input type="radio" name="lang" value="04"><span>Basic</span><br/>
<input type="radio" name="lang" value="05"><span>Fortran</span>
</div>
<script type="text/javascript">
$(function(){
$('#cc').combo({
required:true,
editable:false
});
$('#sp').appendTo($('#cc').combo('panel'));
$('#sp input').click(function(){
var v = $(this).val();
var s = $(this).next('span').text();
$('#cc').combo('setValue', v).combo('setText', s).combo('hidePanel');
});
});
</script>
8、复选框
复选框是在一项或多项内容中,选择零项或者多项的一个输入界面控件。
界面代码如下所示:
<input id="chkIsExpire" type="checkbox" >帐号过期
由于复选框的一些特殊性质,在表单提交的时候,如果没有勾选的选型,使用serializeArray()方法构造的数据,复选框的值则不会被提交。
基于这个原因,我们可以使用Select控件进行替代,实现复选项的功能,而不影响
var postData = $("#ffEdit").serializeArray();
以上代码的使用。
使用Select控件的代码如下所示。
<select id="Visible1" name="Visible">
<option value="true" selected>正常</option>
<option value="false">不可见</option>
</select>
赋值给界面控件代码如下:
$("#Visible1").prop('checked', info.Visible);
获取界面控件的值代码如下:
var visible = $("#txtVisible").val();
9、表格控件DataGrid
easyui的列表控件,可以通过指定table的class属性为easyui-datagrid即可实现表格的定义,界面代码如下所示:
<table class="easyui-datagrid" title="Basic DataGrid" style="width:700px;height:250px"
data-options="singleSelect:true,collapsible:true,url:'../datagrid/datagrid_data1.json'">
<thead>
<tr>
<th data-options="field:'itemid',width:80">Item ID</th>
<th data-options="field:'productid',width:100">Product</th>
<th data-options="field:'listprice',width:80,align:'right'">List Price</th>
<th data-options="field:'unitcost',width:80,align:'right'">Unit Cost</th>
<th data-options="field:'attr1',width:250">Attribute</th>
<th data-options="field:'status',width:60,align:'center'">Status</th>
</tr>
</thead>
</table>
不过为了避免使用脚本定义datagrid导致多次初始化的问题,我们一般只需要指定一个table代码即可,界面如下所示
<table id="grid" style="width: 1024px" title="用户操作" iconcls="icon-view">
</table>
而表格控件的数据加载,我们使用javascript进行初始化,初始化后的表格界面显示效果如下所示。
Javascript代码如下所示,其中的width: function () { return document.body.clientWidth * 0.9 }是用来实现宽度自适应的一个操作。
//实现对DataGird控件的绑定操作
function InitGrid(queryData) {
$('#grid').datagrid({ //定位到Table标签,Table标签的ID是grid
url: '/Menu/FindWithPager', //指向后台的Action来获取当前菜单的信息的Json格式的数据
title: '功能菜单',
iconCls: 'icon-view',
height: 650,
width: function () { return document.body.clientWidth * 0.9 },
nowrap: true,
autoRowHeight: false,
striped: true,
collapsible: true,
pagination: true,
pageSize: 100,
pageList: [50,100,200],
rownumbers: true,
//sortName: 'ID', //根据某个字段给easyUI排序
sortOrder: 'asc',
remoteSort: false,
idField: 'ID',
queryParams: queryData, //异步查询的参数
columns: [[
{ field: 'ck', checkbox: true }, //选择
{ title: '显示名称', field: 'Name', width: 200},
{ title: '图标', field: 'Icon', width: 150 },
{ title: '排序', field: 'Seq', width: 80 },
{ title: '功能ID', field: 'FunctionId', width: 80 },
{ title: '菜单可见', field: 'Visible', width: 80 },
{ title: 'Winform窗体类型', field: 'WinformType', width: 400 },
{ title: 'Web界面Url地址', field: 'Url', width: 200 },
{ title: 'Web界面的菜单图标', field: 'WebIcon', width: 120 },
{ title: '系统编号', field: 'SystemType_ID', width: 80 }
]],
toolbar: [{
id: 'btnAdd',
text: '添加',
iconCls: 'icon-add',
handler: function () {
ShowAddDialog();//实现添加记录的页面
}
}, '-', {
id: 'btnEdit',
text: '修改',
iconCls: 'icon-edit',
handler: function () {
ShowEditOrViewDialog();//实现修改记录的方法
}
}, '-', {
id: 'btnDelete',
text: '删除',
iconCls: 'icon-remove',
handler: function () {
Delete();//实现直接删除数据的方法
}
}, '-', {
id: 'btnView',
text: '查看',
iconCls: 'icon-table',
handler: function () {
ShowEditOrViewDialog("view");//实现查看记录详细信息的方法
}
}, '-', {
id: 'btnReload',
text: '刷新',
iconCls: 'icon-reload',
handler: function () {
//实现刷新栏目中的数据
$("#grid").datagrid("reload");
}
}],
onDblClickRow: function (rowIndex, rowData) {
$('#grid').datagrid('uncheckAll');
$('#grid').datagrid('checkRow', rowIndex);
ShowEditOrViewDialog();
}
})
};
对于查询按钮触发的数据后台查询及数据绑定操作,javascript代码如下所示:
//绑定查询按钮的的点击事件
function BindSearchEvent() {
//按条件进行查询数据,首先我们得到数据的值
$("#btnSearch").click(function () {
//得到用户输入的参数,取值有几种方式:$("#id").combobox('getValue'), $("#id").datebox('getValue'), $("#id").val()
//字段增加WHC_前缀字符,避免传递如URL这样的Request关键字冲突
var queryData = {
WHC_ID: $("#txtID").val(),
WHC_Name: $("#txtName").val(),
WHC_Icon: $("#txtIcon").val(),
WHC_Seq: $("#txtSeq").val(),
WHC_FunctionId: $("#txtFunctionId").val(),
WHC_Visible: $("#txtVisible").val(),
WHC_WinformType: $("#txtWinformType").val(),
WHC_Url: $("#txtUrl").val(),
WHC_WebIcon: $("#txtWebIcon").val(),
WHC_SystemType_ID: $("#txtSystemType_ID").val()
}
//将值传递给
InitGrid(queryData);
return false;
});
}
通过构造一些查询参数并传递相应的值,后台根据这些参数,从对应控制器的分页方法 FindWithPager 获取相应的分页数据,并绑定到grid控件中。
另外,如果需要在grid里面增加一些图片或者链接什么的,应该如何操作呢?
如下界面所示的效果:
首先需要在初始化代码里面增加列的formatter回调函数,如下所示。
columns: [[
{ field: 'ck', checkbox: true }, //选择
{ title: '显示名称', field: 'Name', width: 200},
{ title: '图标', field: 'Icon', width: 150 },
{ title: '排序', field: 'Seq', width: 80 },
{ title: '功能ID', field: 'FunctionId', width: 80 },
{
title: '菜单可见', field: 'Visible', width: 80, formatter: function (val, rowdata, index) {
if (val) {
return '<a class="grid_visible" href="javascript:void(0)" >' + val + '</a>';
} else {
return '<a class="grid_unvisible" href="javascript:void(0)" >' + val + '</a>';
}
}
},
{ title: 'Winform窗体类型', field: 'WinformType', width: 400 },
{ title: 'Web界面Url地址', field: 'Url', width: 200 },
{ title: 'Web界面的菜单图标', field: 'WebIcon', width: 120 },
{ title: '系统编号', field: 'SystemType_ID', width: 80 }
]],
在formatter回调函数里面添加逻辑代码,判断是否可见,其实就是增加两个图片按钮,但是图片按钮的样式设置,必须在加载数据完毕后才能操作,因此需要在函数里面处理。
onLoadSuccess: function () {
$(".grid_visible").linkbutton({ text: '可见', plain: true, iconCls: 'icon-ok' });
$(".grid_unvisible").linkbutton({ text: '不可见', plain: true, iconCls: 'icon-stop' });
},
如果显示的图片不完整,设置行的自动调整高度属性为true即可。
autoRowHeight: true
10、树形控件
虽然easyui也有Tree控件,不过我较喜欢使用zTree这个树形控件,这个是一个免费的Jquery树控件。
引用代码如下所示:
<link href="~/Content/JQueryTools/JQueryTree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" />
<script src="~/Content/JQueryTools/JQueryTree/js/jquery.ztree.core-3.5.min.js" type="text/javascript"></script>
初始化在Tree树控件的界面代码如下所示:
<script type="text/javascript">
<!--
var setting = {
data: {
simpleData: {
enable: true
}
},
callback: {
onClick: onClick,
onDblClick: onDblClick
}
}
//重新加载树形结构(异步)
function reloadTree() {
$("#loading").show();
$.getJSON("/DictType/GetTreeJson?r=" + Math.random(), function (json) {
$.fn.zTree.init($("#treeDemo"), setting, json);
$.fn.zTree.getZTreeObj("treeDemo").expandAll(true);
var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
var treeNodes = treeObj.getNodes();
if (treeNodes != null) {
loadTypeData(treeNodes[0].id);
}
});
$("#loading").fadeOut(500);
}
//树单击节点操作
function onClick(event, treeId, treeNode, clickFlag) {
var id = treeNode.id;
loadTypeData(id);
}
//树双击节点操作
function onDblClick(event, treeId, treeNode) {
var id = treeNode.id;
loadTypeData(id);
ShowDictType('edit');
}
11、布局控件
EasyUI通过DIV层来控制布局的显示,DIV里面增加一个Region的属性用来区分属于哪个区域,如下图是我Web开发框架的界面布局效果图。
界面代码如下所示:
我们详细查看主工作区的代码,如下所示。
<!--主工作区-->
<div id="mainPanle" region="center" title="" style="overflow:hidden;">
<div id="tabs" class="easyui-tabs" fit="true" border="false" >
</div>
</div>
其中字典管理里面还有子布局的展示,我们查看字典管理里面界面代码,如下所示。
<div class="easyui-layout" style="width:700px;height:700px;" fit="true">
<div data-options="region:'west',split:true,title:'字典类别',iconCls:'icon-book'" style="width: 300px; padding: 1px;">
<div style="padding: 1px; border: 1px solid #ddd;">
.......................</div>
<div>
<ul id="treeDemo" class="ztree">
</ul>
</div>
</div>
<div id="tb" data-options="region:'center',title:'字典数据',iconCls:'icon-book'" style="padding:5px;height:auto">
<!-------------------------------详细信息展示表格----------------------------------->
<table id="grid" style="width: 940px" title="用户操作" iconcls="icon-view"></table>
</div>
</div>
12、弹出式对话框
EasyUI弹出式对话框用的很多,对话框的界面代码放在DIV层里面,一般在界面整个界面加载后中已经初始化了,只是我们根据条件相似适当的层即可,这样就形成了弹出式对话框,弹出式对话框有一个遮罩的效果。
界面代码如下所示:
13、提示信息
在常规的Web界面提示里面,我们一般用纯粹的javascript的alert函数来进行信息的提示,如果在基于EasyUI的界面布局和演示里面,使用这个提示显然会和界面演示不够匹配,因此我们使用messager类来进行相应的提示信息处理,简单的脚本提示代码如下。
$.messager.alert("提示", "修改成功");
提示信息也可以更加丰富,添加图标等信息,界面代码如下所示。
<script>
function alert1(){
$.messager.alert('My Title','Here is a message!');
}
function alert2(){
$.messager.alert('My Title','Here is a error message!','error');
}
function alert3(){
$.messager.alert('My Title','Here is a info message!','info');
}
function alert4(){
$.messager.alert('My Title','Here is a question message!','question');
}
function alert5(){
$.messager.alert('My Title','Here is a warning message!','warning');
}
</script>
对于一般的删除操作,一般有一个提示确认的消息框,这个messager类也进行了封装处理,效果也不错。
界面代码如下所示。
$.messager.confirm("删除确认", "您确认删除选定的记录吗?", function (deleteAction) {
if (deleteAction) {
$.get("/DictData/DeletebyIds", postData, function (data) {
if (data == "true") {
$.messager.alert("提示", "删除选定的记录成功");
$("#grid").datagrid("reload");
//当删除完成之后,第二次删除的时候还记得上次的信息,这样是不可以的,所以我们需要清除第一次的信息
rows.length = "";//第一种方法
$("#grid").datagrid("clearSelections");//第二种方法
}
else {
$.messager.alert("提示", data);
}
});
}
});
以上就是我Web开发框架里面常用到的一些界面控件展示以及相关的代码介绍,有一些不太常用的控件可能还没有在本文中介绍,欢迎大家进行补充和讨论,以后有时间继续完善这个文章,作为基于MVC+EasyUI的框架界面的一个很好的参考。希望大家喜欢,多多提意见。
基于MVC4+EasyUI的Web开发框架的系列文章:
基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍
基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计
基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用
基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用
基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍
基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作
基于MVC4+EasyUI的Web开发框架形成之旅--权限控制
基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录
基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面
基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据
基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts
基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder
基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理
基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动
基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览
基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作
基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出
基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码
基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式
基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度
基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作
本文转自博客园伍华聪的博客,原文链接:基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用,如需转载请自行联系原博主。
基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出
数据的导入导出,在很多系统里面都比较常见,这个导入导出的操作,在Winform里面比较容易实现,我曾经在之前的一篇文章《Winform开发框架之通用数据导入导出操作》介绍了在Winform里面的通用导入导出模块的设计和开发过程,但在Web上我们应该如何实现呢?本文主要介绍利用MVC4+EasyUI的特点,并结合文件上传控件Uploadify 的使用,实现文件上传后马上进行处理并显示,然后确认后把数据写入数据库的过程。
我们知道,Web上对Excel的处理和Winform的有所差异,如果是在Web上处理,我们需要把Excel文档上传到服务器上,然后读取文件进行显示,所以第一步是实现文件的上传操作,关于文件上传控件,具体可以参考我的文章《基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用》。
1、导入数据的界面效果展示
在Winform里面,我们处理Excel数据导入的界面如下所示。
在Web上的主界面如下所示。
导入界面如下所示。
2、Web数据导入的处理逻辑和代码
为了实现Web上的数据导入导出操作,我们需要增加两个按钮,一个是导入按钮,一个是导出按钮。
<a href="javascript:void(0)" class="easyui-linkbutton" id="btnImport" iconcls="icon-excel" onclick="ShowImport()">导入</a>
<a href="javascript:void(0)" class="easyui-linkbutton" id="btnExport" iconcls="icon-excel" onclick="ShowExport()">导出</a>
导入的JS处理代码如下所示。
//显示导入界面
function ShowImport() {
$.showWindow({
title: '客户联系人-Excel数据导入',
useiframe: true,
width: 1024,
height: 700,
content: 'url:/Contact/Import',
buttons: [{
text: '取消',
iconCls: 'icon-cancel',
handler: function (win) {
win.close();
}
}]
});
}
上面主要就是弹出一个窗口(上面的导入数据窗口),用来方便客户选择Excel文件并保存数据或者下载导入模板等操作的。
然后在Import.cshtml的视图代码里面,我们需要初始化Datagrid和相关的界面元素,初始化DataGrid的代码如下所示。
//实现对DataGird控件的绑定操作
function InitGrid() {
var guid = $("#AttachGUID").val();
$('#grid').datagrid({ //定位到Table标签,Table标签的ID是grid
url: '/Contact/GetExcelData?guid=' + guid, //指向后台的Action来获取当前用户的信息的Json格式的数据
title: '客户联系人-Excel数据导入',
iconCls: 'icon-view',
height: 400,
width: function () { return document.body.clientWidth * 0.9 },//自动宽度
..................
上面红色部分的内容,就是我们在文件顺利上传到服务器上的时候,根据一个guid的参数初始化DataGrid的列表数据。
下面是附件上传控件uploadify的初始化脚本代码,其中红色部分注意一下,我们需要上传的是一个文件,并且不允许多选,限定上传文件的类型为xls。
文件上传完成后,首先调用CheckExcelColumns控制器函数来检查是否匹配导入模板的字段,如果匹配通过,加载Excel并展示数据到Datagrid里面,否则提示用户按模板格式录入数据。
<script type="text/javascript">
$(function () {
//添加界面的附件管理
$('#file_upload').uploadify({
'swf': '/Content/JQueryTools/uploadify/uploadify.swf', //FLash文件路径
'buttonText': '浏 览', //按钮文本
'uploader': '/FileUpload/Upload', //处理ASHX页面
'queueID': 'fileQueue', //队列的ID
'queueSizeLimit': 1, //队列最多可上传文件数量,默认为999
'auto': false, //选择文件后是否自动上传,默认为true
'multi': false, //是否为多选,默认为true
'removeCompleted': true, //是否完成后移除序列,默认为true
'fileSizeLimit': '10MB', //单个文件大小,0为无限制,可接受KB,MB,GB等单位的字符串值
'fileTypeDesc': 'Excel Files', //文件描述
'fileTypeExts': '*.xls', //上传的文件后缀过滤器
'onQueueComplete': function (event, data) { //所有队列完成后事件
var guid = $("#AttachGUID").val();
ViewUpFiles(guid, "div_files");
//提示用户Excel格式是否正常,如果正常加载数据
$.ajax({
url: '/Contact/CheckExcelColumns?guid=' + guid,
type: 'get',
dataType:'json',
success: function (data) {
if (data.Success) {
InitGrid(); //重新刷新表格数据
$.messager.alert("提示", "文件已上传,数据加载完毕!");
}
else {
$.messager.alert("提示", "上传的Excel文件检查不通过。请根据页面右上角的Excel模板格式进行数据录入。");
}
}
});
},
'onUploadStart': function (file) {
InitUpFile();//上传文件前 ,重置GUID,每次不同
$("#file_upload").uploadify("settings", 'formData', { 'folder': '数据导入文件', 'guid': $("#AttachGUID").val() }); //动态传参数
},
'onUploadError': function (event, queueId, fileObj, errorObj) {
//alert(errorObj.type + ":" + errorObj.info);
}
});
});
为了有效处理数据的导入,我们需要严格保证导入的数据是和模板的字段是匹配的,否则处理容易出错,也没有任何意义。为了实现这个目的,框架里面提供方法对字段进行检查,主要是确保Excel里面包含了完整的字段即可。
/// <summary>
/// 检查Excel文件的字段是否包含了必须的字段
/// </summary>
/// <param name="guid">附件的GUID</param>
/// <returns></returns>
public ActionResult CheckExcelColumns(string guid)
{
CommonResult result = new CommonResult();
try
{
DataTable dt = ConvertExcelFileToTable(guid);
if (dt != null)
{
//检查列表是否包含必须的字段
result.Success = DataTableHelper.ContainAllColumns(dt, columnString);
}
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
result.ErrorMessage = ex.Message;
}
return ToJsonContent(result);
}
而在InitGrid的初始化中的这个GetExcelData的控制器方法如下所示。主要的逻辑就是获取到Excel,并把Excel里面的数据转换为DataTable,最后初始化为实体类列表,并返回给调用页面就可以了。
/// <summary>
/// 获取服务器上的Excel文件,并把它转换为实体列表返回给客户端
/// </summary>
/// <param name="guid">附件的GUID</param>
/// <returns></returns>
public ActionResult GetExcelData(string guid)
{
if (string.IsNullOrEmpty(guid))
{
return null;
}
List<ContactInfo> list = new List<ContactInfo>();
DataTable table = ConvertExcelFileToTable(guid);
if (table != null)
{
#region 数据转换
int i = 1;
foreach (DataRow dr in table.Rows)
{
string customerName = dr["客户名称"].ToString();
if (string.IsNullOrEmpty(customerName))
{
continue;//客户名称为空,记录跳过
}
CustomerInfo customerInfo = BLLFactory<Customer>.Instance.FindByName(customerName);
if (customerInfo == null)
{
continue;//客户名称不存在,记录跳过
}
ContactInfo info = new ContactInfo();
info.Customer_ID = customerInfo.ID;//客户ID
info.HandNo = dr["编号"].ToString();
info.Name = dr["姓名"].ToString();
..............................//增加一个特殊字段的转义
info.Data1 = BLLFactory<Customer>.Instance.GetCustomerName(info.Customer_ID);
list.Add(info);
}
#endregion
}
var result = new { total = list.Count, rows = list };
return JsonDate(result);
}
3、Web上数据的导出操作
刚才介绍了数据的导入操作,数据的导出操作相对简单一些,它的JS函数操作如下所示。
//导出Excel数据
var exportCondition;
function ShowExport() {
var url = "/Contact/Export";
$.ajax({
type: "POST",
url: url,
data: exportCondition,
success: function (filePath) {
var downUrl = '/FileUpload/DownloadFile?file=' + filePath;
window.location = downUrl;
}
});
}
虽然数据的导出比较简单一点,但是由于我们需要使用POST方式对数据条件进行提交,因此不像普通的方式下载文件Window.Open(url)就可以实现文件下载了。如果POST方式提交了参数,那么返回的数据即使是文件流,也无法进行有效的下载。
从上面的脚本我们可以看到,里面的exportCondition就是我们需要提交到服务器的条件,服务器根据这个条件进行检索数据,并返回一个Excel文件就可以了。
由于使用ajax这种POST方式无法直接下载文件流,因此,我们需要先根据条件,在服务器上生成文件,返回一个文件路径,再次通过DownloadFile方法进行文件的下载才可以。
因此这个传递的条件也是很重要的,在查询操作的时候,我们可以把对应的条件传递给它。
//绑定搜索按钮的的点击事件
function BindSearchEvent() {
//按条件进行查询数据,首先我们得到数据的值
$("#btnSearch").click(function () {
//得到用户输入的参数
//取值有几种方式:$("#id").combobox('getValue'), $("#id").datebox('getValue'), $("#id").val(),combotree('getValue')
//字段增加WHC_前缀字符,避免传递如URL这样的Request关键字冲突
var queryData = {
WHC_Name: $("#txtName").val(),
WHC_OfficePhone: $("#txtOfficePhone").val(),
WHC_Mobile: $("#txtMobile").val(),
WHC_Address: $("#txtAddress").val(),
WHC_Email: $("#txtEmail").val(),
WHC_Note: $("#txtNote").val()
}
//将值传递给DataGrid
InitGrid(queryData);
//传递给导出操作
exportCondition = queryData;
return false;
});
}
在我们选定某个树的节点的时候,我们也可以传递自定义的条件给它。
//根据消息分组加载指定列表
function loadByGroupTree(node) {
//赋值给特殊字段,公司和部门查询的时候选择其中一个
var queryParams = $('#grid').datagrid('options').queryParams;
var condition = "{ id: \"" + node.id +"\", groupname:\"" + node.text +"\", userid:\"" + @Session["UserId"] + "\" }";
queryParams.CustomedCondition = condition;//提供给datagrid的条件
exportCondition = { CustomedCondition: condition };//提供给导出的条件
$("#grid").datagrid("reload");
$('#grid').datagrid('uncheckAll');
}
后台的Export控制器方法主要的逻辑如下所示。
最终是返回一个生成好的文件地址。
最后给一个方法直接下载文件就可以了。
/// <summary>
/// 根据路径下载文件,主要用于生成的文件的下载
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns></returns>
public ActionResult DownloadFile(string file)
{
string realPath = Server.MapPath(file);
string saveFileName = FileUtil.GetFileName(realPath);
Response.WriteFile(realPath);
Response.Charset = "GB2312";
Response.ContentEncoding = Encoding.GetEncoding("GB2312");
Response.ContentType = "application/ms-excel/msword";
Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(saveFileName));
Response.Flush();
Response.End();
return new FileStreamResult(Response.OutputStream, "application/ms-excel/msword");
}
导出的Excel界面效果如下所示。
由于篇幅的原因,这个导入导出的操作就介绍到这里,希望有问题大家共同探讨。
基于MVC4+EasyUI的Web开发框架的系列文章:
基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍
基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计
基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用
基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用
基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍
基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作
基于MVC4+EasyUI的Web开发框架形成之旅--权限控制
基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录
基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面
基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据
基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts
基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder
基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理
基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动
基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览
基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作
基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出
基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码
基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式
基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度
基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作
本文转自博客园伍华聪的博客,原文链接:基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出,如需转载请自行联系原博主。
基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作
在很多Web系统中,一般都可能提供一些图标的选择,方便配置按钮,菜单等界面元素的图标,从而是Web系统界面看起来更加美观和协调。但是在系统中一般内置的图标样式相对比较有限,而且硬编码写到样式表里面,这样给我们扩展使用有很多的不方便。基于这个原因,我想如果能够独立一个模块,自动根据图标生成图标CSS样式文件,并存储相应的记录到数据库里面,方便我们查询显示,那样我们使用起来就很方便了,最后有了这些数据,只需要做一个通用的图标选择界面,并可以在很多地方重用了。本文正是基于这个思路,开发了一个图标管理模块和图标选择界面,本文主要阐述这个开发过程和最终的效果展示。
1、图标样式生成管理
为了方便根据读取的图标文件列表,生成对应的图标样式文件,我们可以利用NVelocity组件,基于模板进行CSS样式文件的生成。关于NVelocity的使用,可以参考我多篇关于它的介绍,这个组件非常强大,我自己的代码生成工具也是基于它编写了很多模板进行代码生成,具体可以参考一下《使用NVelocity生成内容的几种方式》这篇文章。
1.1 图标样式文件准备
有了这些准备,我们可以定义一个模板的文件用来生成样式文件了,我们先看最终的样式文件效果。
.icon-table{
background:url('table.png') no-repeat center center;
}
.icon-telephone{
background:url('telephone.png') no-repeat center center;
}
.icon-user{
background:url('user.png') no-repeat center center;
}
.icon-view{
background:url('view.png') no-repeat center center;
}
.icon-word{
background:url('word.png') no-repeat center center;
}
根据以上组织效果,我们可以定义一个模板内容如下所示。
#foreach($item in ${FileNameList})
.${item.Text}{
background:url('${item.Value}') no-repeat center center;
}
#end ##endforeach
其中FileNameList变量是一个基于名称和值的集合对象,我们遍历它进行生成就可以了。
1.2 图标样式的生成操作
有了模板,我们还需要组织好对应的文件目录,一般来说,Web的图标可以使用16,24,32这些标准大小的图表,适应不同场合的需要。
因此我们创建几个不同的目录,并放入对应的模板文件和图标文件。
生成图标样式文件的操作分为下面几个步骤:
获取对应目录的图标文件,转换为实际的对象格式集合,生成图标样式文件,存储图表样式到数据库方便查询。
这些操作我们在图标管理的控制器 IconController 里面增加方法完成,部分代码如下所示。
/// <summary>
/// 生成图标文件
/// </summary>
/// <param name="iconSize">图表尺寸,可选16,32等</param>
/// <returns></returns>
public ActionResult GenerateIconCSS(int iconSize = 16)
{
CommonResult result = new CommonResult();
string realPath = Server.MapPath("~/Content/icons-customed/" + iconSize);
if (Directory.Exists(realPath))
{
List<CListItem> list = GetImageToList(realPath, iconSize);
try
{
//使用相对路径进行构造处理
string template = string.Format("Content/icons-customed/{0}/icon.css.vm", iconSize);
NVelocityHelper helper = new NVelocityHelper(template);
helper.AddKeyValue("FileNameList", list);
helper.FileNameOfOutput = "icon";
helper.FileExtension = ".css";
helper.DirectoryOfOutput = realPath;//指定实际路径
string outputFilePath = helper.ExecuteFile();
if (!string.IsNullOrEmpty(outputFilePath))
{
result.Success = true;
//写入数据库
bool write = BLLFactory<Icon>.Instance.BatchAddIcon(list, iconSize);
}
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
result.ErrorMessage = ex.Message;
}
}
else
{
result.ErrorMessage = "没有找到图片文件";
}
return ToJsonContent(result);
}
上面的方法很好的完成了对图标样式的生成和保存数据库的操作,这个生成操作主要就是基于模板化的生成,非常方便。
在构建名称值的集合的时候,注意图标样式名称,不能包含有 一些特殊的字符,如[]()这些符号需要去掉,因此可以通过下面的正则表达式替换方法进行去除。
string displayText = Path.GetFileNameWithoutExtension(file);
//文件名需要去除()和[]等符号
displayText = CRegex.Replace(displayText, @"[)\];,\t\r ]|[\n]", "", 0);
displayText = CRegex.Replace(displayText, @"[(\[]", "-", 0);
最终,我们可以构建一个独立的页面,用来实现生成图标样式并保存的操作,界面如下所示。
界面操作代码如下所示。
//绑定按钮的的点击事件
function BindEvent() {
$("#btnGenerateCSS").click(function () {
$.messager.confirm("操作确认", "您确认重新生成图标记录吗?", function (action) {
if (action) {
//图表尺寸
var iconSize = $("#IconSize").combobox('getValue');
//alert(iconSize);
var postData = "";
$.ajax({
type: 'POST',
url: '/Icon/GenerateIconCSS?iconSize=' + iconSize,
dataType: 'json',
data: postData,
success: function (data) {
if (data.Success) {
showTips("操作成功");
location.reload();
}
else {
showError("操作失败:" + data.ErrorMessage, 3000);
}
}
});
}
});
});
}
2、图标的分页展示
为了有效查看我们生成在数据库的图标列表,我们需要一个合理的界面表现方式,用来显示图标信息。传统的使用datagrid的方式比较呆板,也不是很方便,所以我们需要自定义分页处理进行展现,基于重用一些优秀组件的原则,我侧重于使用一些现成的组件模块,MVC分页方面,考虑使用杨涛的MVC分页控件(http://www.webdiyer.com/mvcpager/),这个功能看起来很不错。
图表的展现方式,我希望通过easyui的这个例子进行展现一组图表的效果。
2.1 图表展现的界面效果
然后系统通过把它们进行分页处理,选择一些好的分页样式表现方式
最终实现的图表样式显示效果如下所示。
小图标效果如下所示。
大图标效果如下所示。
2.2 图标的分页处理操作
杨涛的分页控件,提供了很多绑定分页的方式,不过都主要是基于MVC的模型数据处理,在我的Web框架里面主要利用JS绑定数据,有 一定的差异,但是既然大家都是MVC应用,整合还是没问题的。
为了展现上面的效果,我们需要建立一个表单查询的内容,代码如下所示。
<fieldset>
<legend>功能操作</legend>
@using (Html.BeginForm("select", "Icon", new RouteValueDictionary { { "id", "" } }, FormMethod.Get))
{
<span>尺寸:</span>
<select class="easyui-combobox" id="IconSize" name="IconSize" style="width:100px">
<option value="16">16×16</option>
<option value="24">24×24</option>
<option value="32">32×32</option>
</select>
<input type="submit" value="搜索(S)" accesskey="S" />
}
</fieldset>
数据内容的展现,主要就是利用了easyUI的样式,创建一些linkbutton的代码,代码如下所示。这里注意的是,我也是用了model,它是PagedList<WHC.MVCWebMis.Entity.IconInfo>类型的。
也就是说,最终这个视图界面后台,是有一个模型的绑定的。
<div id="contents">
@using Webdiyer.WebControls.Mvc;
@model PagedList<WHC.MVCWebMis.Entity.IconInfo>
@foreach (var item in Model)
{
<a href="javascript:void(0)" class="easyui-linkbutton" onclick="SelectItem(this, '@item.IconCls')" id="@item.ID" data-options="plain:true,iconCls:'@item.IconCls',size:'large',toggle:true"> </a>
}
</div>
图标后台处理的控制器方法如下所示。
/// <summary>
/// 根据条件获取基于PagedList的对象集合,并返回给分页视图使用
/// </summary>
/// <param name="id">分页页码</param>
/// <param name="iconsize">图标尺寸</param>
/// <returns></returns>
private PagedList<IconInfo> GetPageList(int? id, int? iconsize = 16)
{
int size = iconsize ?? 16;
int pageIndex = id ?? 1;
int pageSize = 200;
PagerInfo pagerInfo = new PagerInfo();
pagerInfo.CurrenetPageIndex = pageIndex;
pagerInfo.PageSize = pageSize;
string where = string.Format("iconsize = {0}", size);
List<IconInfo> list = BLLFactory<Icon>.Instance.FindWithPager(where, pagerInfo);
PagedList<IconInfo> pageList = pageList = new PagedList<IconInfo>(list, pageIndex, pageSize, pagerInfo.RecordCount);
return pageList;
}
/// <summary>
/// 根据条件获取分页数据集合,并绑定到视图里面
/// </summary>
/// <param name="id">分页页码</param>
/// <param name="iconsize">图标尺寸</param>
/// <returns></returns>
public ActionResult Select(int? id = 1, int? iconsize = 16)
{
PagedList<IconInfo> pageList = GetPageList(id, iconsize);
return View("select", pageList);
}
最后部分是分页部分的展现了,就是在底部展现各页的页码等信息了。
这个部分很简单,代码如下所示。
<div>
<div style="float:left;width:50%">
共 @Model.TotalPageCount 页 @Model.TotalItemCount 条记录,当前为第 @Model.CurrentPageIndex 页
</div>
@Html.Pager(Model, new PagerOptions { PageIndexParameterName = "id" }, new { style = "float:right", id = "badoopager" })
</div>
在分页的时候,可能很多时候,发现更新页面后,条件就消失了,这种情况是因为没有很好绑定条件的值到界面上,我们可以通过页面加载完成后,把URL里面的参数值赋值给控件就可以了。
$(function () {
var iconSize = '@Request.QueryString["iconSize"]';
if(iconSize != undefined && iconSize != "")
{
$("#IconSize").combobox('setValue', iconSize);
}
});
这样图表大小的条件就一直可以保持正确的内容,提交表单后依旧可以正常保持了。
3、图标的选择
既然生成了图标文件,并且构建了图标的展示界面,那么我们就需要在一些需要配置图标的地方,能够提供一个界面选择图标了。
绑定弹出选择图标界面操作,在EasyUI的基础上,使用了扩展对话框的操作,可以弹出一个外部页面的选择图标菜单。
function SelectIcon(id, value) {
$.showWindow({
title: '选择图标',
useiframe: true,
width: 960,
height: 640,
content: 'url:/Icon/Select',
data: { id: $(id), value: $(value) },
buttons: [{
text: 'OK',
iconCls: 'icon-ok',
handler: 'doOK' //此方法在_content3.html中
}, {
text: '取消',
iconCls: 'icon-cancel',
handler: function (win) {
win.close();
}
}],
onLoad: function (win, content) {
//window打开时调用,初始化form内容
if (content) {
content.doInit(win);
}
}
});
}
//绑定选择按钮的事件
function BindSelectIconEvent() {
$("#tdIcon").click(function () { SelectIcon("#imgIcon", "#WebIcon") });
$("#tdIcon1").click(function () { SelectIcon("#imgIcon1", "#WebIcon1") });
}
选择好每个图标后,我们就会返回到主界面上,并设置好主界面上的图表样式,让它显示出我们选择的图标效果。
基于MVC4+EasyUI的Web开发框架的系列文章:
基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍
基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计
基于MVC4+EasyUI的Web开发框架形成之旅--界面控件的使用
基于MVC4+EasyUI的Web开发框架形成之旅--附件上传组件uploadify的使用
基于MVC4+EasyUI的Web开发框架形成之旅--框架总体界面介绍
基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作
基于MVC4+EasyUI的Web开发框架形成之旅--权限控制
基于MVC4+EasyUI的Web开发框架经验总结(1)-利用jQuery Tags Input 插件显示选择记录
基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面
基于MVC4+EasyUI的Web开发框架经验总结(3)- 使用Json实体类构建菜单数据
基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts
基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder
基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理
基于MVC4+EasyUI的Web开发框架经验总结(7)--实现省份、城市、行政区三者联动
基于MVC4+EasyUI的Web开发框架经验总结(8)--实现Office文档的预览
基于MVC4+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作
基于MVC4+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出
基于MVC4+EasyUI的Web开发框架经验总结(11)--使用Bundles处理简化页面代码
基于MVC4+EasyUI的Web开发框架经验总结(12)--利用Jquery处理数据交互的几种方式
基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度
基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作
本文转自博客园伍华聪的博客,原文链接:基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作,如需转载请自行联系原博主。
JQuery Easy Ui (Tree树)详解(转)
第一讲:JQuery Easy Ui到底是什么呢?
首先咱们知道JQuery是对Java Script的封装,是一个js库,主要提供的功能是选择器,属性修改和事件绑定等等。。
JQuery ui是在jQuery的基础上,利用jQuery的扩展性,设计的插件。
那么JQuery Easy Ui到底是什么呢?
我的理解就是比JQuery ui更强大,同样都是实现绚丽的多功能效果!
jQuery Easy UI的目的就是帮助Web开发者更轻松的打造出功能更丰富并且更美观的UI界面。
当然JQuery Easy ui提供了用于创建跨浏览器网页的完整的组件集合,
包括功能强大的 datagrid(数据网格)、treegrid(树形表格)、 panel(面板)、combo(下拉组合)等等。
用户可以组合使用这些组件,也可以单独使用其中一个。
其实就这么简单,对某个事物的定义,个人感觉没有什么固定的答案,只是那种答案更方便你的记忆,
你记住的,它存在你深深的脑海里的,便是答案!
JQuery Easy Ui插件列表如下:
分类
插件
Base(基础)
Parser 解析器
Easyloader 加载器
Draggable 可拖动
Droppable 可放置
Resizable 可调整尺寸
Pagination 分页
Searchbox 搜索框
Progressbar 进度条
Tooltip 提示框
Layout(布局)
Panel 面板
Tabs 标签页/选项卡
Accordion 折叠面板
Layout 布局
Menu(菜单)与 Button(按钮)
Menu 菜单
Linkbutton 链接按钮
Menubutton 菜单按钮
Splitbutton 分割按钮
Form(表单)
Form 表单
Validatebox 验证框
Combo 组合
Combobox 组合框
Combotree 组合树
Combogrid 组合网格
Numberbox 数字框
Datebox 日期框
Datetimebox 日期时间框
Calendar 日历
Spinner 微调器
Numberspinner 数值微调器
Timespinner 时间微调器
Slider 滑块
Window(窗口)
Window 窗口
Dialog 对话框
Messager 消息框
DataGrid(数据网格)与 Tree(树)
Datagrid 数据网格
Propertygrid 属性网格
Tree 树
Treegrid 树形网格
但是今天咱们只针对Tree(树)连接数据进行讲解!
下面是它的一些基本的属性:
id: 绑定到节点的标识值;
text:显示文本;
iconCls: 显示icon的css样式;
checked: 节点是否选中;
state: 节点状态, 'open' 或者 'closed';
attributes: 绑定到节点的自定义属性;
target: 目标 DOM 对象;
children: 一个节点数组,定义一些子节点。
特性
名称
类型
说明
默认值
url
string
获取远程数据的 URL 。
null
method
string
获取数据的 http method 。
post
animate
boolean
定义当节点展开折叠时是否显示动画效果。
false
checkbox
boolean
定义是否在每个节点前边显示 checkbox 。
false
cascadeCheck
boolean
定义是否级联检查。
true
onlyLeafCheck
boolean
定义是否只在叶节点前显示 checkbox 。
false
dnd
boolean
定义是否启用拖放。
false
data
array
加载的节点数据。
null
事件
名称
参数
说明
onClick
node
当用户点击一个节点时触发, node 参数包含下列特性: id:节点的 id text:节点的文字 checked:节点是否被选中 attributes:节点自定义属性 target:被点击目标的 DOM 对象
onDblClick
node
当用户双击一个节点时触发。
onBeforeLoad
node, param
当加载数据的请求发出前触发,返回 false 就取消加载动作。
onLoadSuccess
node, data
当数据加载成功时触发。
onLoadError
arguments
当数据加载失败时触发, arguments 参数与 jQuery.ajax 的'error' 函数一样。.
onBeforeExpand
node
节点展开前触发,返回 false 就取消展开动作。
onExpand
node
当节点展开时触发。
onBeforeCollapse
node
节点折叠前触发,返回 false 就取消折叠动作。
onCollapse
node
当节点折叠时触发。
onCheck
node, checked
当用户点击 checkbox 时触发。
onBeforeSelect
node
节点被选中前触发,返回 false 就取消选择动作。
onSelect
node
当节点被选中时触发。
onContextMenu
e, node
当右键点击节点时触发。
onDrop
target, source, point
当节点被拖拽施放时触发。 target:DOM 对象,拖放的目标节点。 source:源节点。 point:表示拖放操作,可能是值是: 'append'、'top' 或 'bottom'。
onBeforeEdit
node
编辑节点前触发。
onAfterEdit
node
编辑节点后触发。
onCancelEdit
node
当取消编辑动作时触发。
方法
名称
参数
说明
options
none
返回树的 options。
loadData
data
加载树的数据。
getNode
target
获取指定的节点对象。
getData
target
获取指定的节点数据,包括它的子节点。
reload
target
重新加载树的数据。
getRoot
none
获取根节点,返回节点对象。
getRoots
none
获取根节点们,返回节点数组。
getParent
target
获取父节点, target 参数指节点的 DOM 对象。
getChildren
target
获取子节点, target 参数指节点的 DOM 对象。
getChecked
none
获取所有选中的节点。
getSelected
none
获取选中的节点并返回它,如果没有选中节点,就返回 null。
isLeaf
target
把指定的节点定义成叶节点, target 参数表示节点的 DOM 对象。
find
id
找到指定的节点并返回此节点对象。
select
target
选中一个节点, target 参数表示节点的 DOM 对象。
check
target
把指定节点设置为勾选。
uncheck
target
把指定节点设置为未勾选。
collapse
target
折叠一个节点, target 参数表示节点的 DOM 对象。
expand
target
展开一个节点, target 参数表示节点的 DOM 对象。
collapseAll
target
折叠所有的节点们。
expandAll
target
展开所有的节点们。
expandTo
target
从指定节点的根部展开。
append
param
追加一些子节点们到一个父节点, param 参数有两个特性: parent:DOM 对象,追加到的父节点,如果没有分配,则追加为根节点。 data:数组,节点们的数据。
toggle
target
切换节点的展开/折叠状态, target 参数表示节点的 DOM 对象。
insert
param
在指定节点的前边或后边插入一个节点, param 参数包含下列特性: before:DOM 对象,前边插入的节点。 after:DOM 对象,后边插入的节点。 data:对象,节点数据。
remove
target
移除一个节点和它的子节点们, target 参数表示节点的 DOM 对象。
pop
target
弹出一个节点和它的子节点们,此方法和 remove 一样,但是返回了移除的节点数据。
update
param
跟心指定的节点, param 参数有下列特性: target(DOM 对象,被更新的节点)、id、text、iconCls、checked、等等。
enableDnd
none
启用拖放功能。
disableDnd
none
禁用拖放功能。
beginEdit
nodeEl
开始编辑节点。
endEdit
nodeEl
结束编辑节点。
cancelEdit
nodeEl
取消编辑节点。
下面有具体的Demo给大家更直观的理解!
既然咱们知道了JQuery Easy ui是什么了,那它到底怎么用那?
试想一下? 咱们怎么用的JQuery?不就是引用了它的JS库吗?
JQuery Easy ui也不例外,引用了它相关的JS库,咱们便能驾驭它了。
切记:引用的顺序不能颠倒,否则实现不了咱们想象的效果!
好了,下面就来看一下,引用JQuery Easy ui的js库时,顺序到底是怎样的呢?
第二讲:引用JQuery Easy ui的JS库顺序(凡事有先后)
引用顺序如下:
1:首先引用JQuery的核心库
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
2:引入 EasyUI 核心 UI 文件 CSS,我的jquery-easyui版本是1.2.6
<link rel="stylesheet" href="jquery-easyui-1.2.6/themes/default/easyui.css" type="text/css"/>
3:引入 EasyUI 图标文件
<link rel="stylesheet" href="jquery-easyui-1.2.6/themes/icon.css" type="text/css"/>
4:引入 jQuery EasyUI 核心库
<script type="text/javascript" src="jquery-easyui-1.2.6/jquery.easyui.min.js"></script>
5:咱们是伟大的中国人,所以要引入 EasyUI 中文提示信息 <script type="text/javascript" src="jquery-easyui-1.2.6/locale/easyui-lang-zh_CN.js"></script>
这个顺序,不要颠倒啊!错了,后果自负哦!亲!
为了给大家一个更深刻的印象,咱们来写一个例子,以便于大家更好的消化和理解!
咱们这个例子就以Tree(树)来进行!
废话不多说,直接上代码#24 哈哈!!!! 我又笑了!
第三讲:Tree(树)(我的心情谁能懂?)
我的步骤,很详细,希望同志们认真看,肯定都能看懂,看明白!谢谢!
第一步:创建一个MVC项目,具体实现看图!
点击确定后的效果图如下:
点击确定后的效果图如下:
第二步:创建控制器和对应的试图:
具体步骤看下图:
点击添加后的效果图如下:
点击添加后的效果图如下:
点击添加后的效果图如下:
点击添加后咱们的控制器和试图就创建完毕了。
第三步:创建数据库实体模型
同志们:咱们要实现和数据库交互,首先数据库得有吧。
咱们得在咱们的MVC项目中创建出数据库的实体模型吧!
关于怎么创建数据库,我在这里就不一一讲解了,但是,又怕
有些同志不是很清楚,我就乐此不疲的再给大家截图,
只要读者有收获,我的努力就没白费!
知识本身就是用来分享的!
数据库那边的效果图如下:
下面是数据表中的数据:
以上两个图片就是数据库那边的基本信息了,
同志们只需要知道,咱们已经有需要交互的数据库就行了,
下面咱们开始来看看:
怎么才能与数据库产生交互那?
怎么才能创建数据库实体模型那?
具体实现看下图:
点击新建项后的效果图如下:
点击添加后的效果图如下:
点击下一步后的效果图如下:
点击新建连接后的效果图如下:
温馨提示:
不要点击 服务器名 框中的↓ 按钮,
我反正是一点就卡,在此提醒下同志们,
直接在框中输入 . (点)就OK!
具体填写如下图:
点击确定后的效果图如下:
点击下一步后的效果图如下:
点击下一步后的效果图如下:
点击完成后的效果图如下:
对项目点击右键,重新生成后,咱们的第三步就就完成了!
第四步:既然咱们学的是JQuery Easy Ui,所以咱们得把咱们下载好的JQuery Easy Ui移到项目中来
这个内容就不用我截图了吧?就是复制粘贴!
算了,我还是有点不放心,还是截图吧!#99
下载,我就不说了,我想同志们都会!
1:找到电脑中下载好的JQuery Easy Ui文件夹,复制
如下图:
2:选中项目名称,粘贴
如下图:
第五步:进入控制器,书写代码
咱们刚才已经创建了数据库的实体模型,但是,该怎么使用那?
首先咱们要找到数据库数据模型的上下文,在哪里那?
在下图中:
打开后的效果图如下:
找到了deptEntities,咱们就可以开始写代码了!
希望同志们打起精神来了,上面虽然篇幅很多,但是没多少干货!
下面很重要,各位打起12分的精神!Go! Go!! Go!!!
控制器中的代码如下:
以上就是控制器中的所有代码了。您要是看不懂我也是醉了!!!
下面咱们再来写一下View试图中的代码!
代码如下:
上文的animate就是当展开或者折叠节点的时候,是否显示效果!在这里重申一下,
怕有的同志忘记了!
好了,点击运行,查看效果吧!!!
效果图就出来了,终于快完成我的使命了!!!
真心希望大家有所收获!!!
http://www.cnblogs.com/999-/p/4488660.html
常用的CSS框架
常用的CSS框架
之前在写自己的个人网站的时候,由于自己Web前端不是特别好,于是就去找相关的CSS框架来搭建页面了。
找到以下这么一篇文章(列出了很多常用的CSS框架):
http://w3schools.wang/report/top-UI-open-source-framework-summary.html
Bootstrap
Semantic-ui
Foundation
Materialize
Material-ui
Phantomjs
Pure
Flat-ui
Jquery-ui
React-bootstrap
Uikit
Metro-ui-css
Iview
Layui
Mui
Frozenui
AlloyUI
W3.CSS
本篇主要是记录我用过的CSS框架,并把之前写过的笔记进行整合一下。当然是不能面面俱到的...
jquery-easyUI
其实这个已经是比较早的了,只是之前学过了一点,做过笔记才拿到这里来。毕竟可能以后还是会用到的?
什么是easyUI
我们可以看官方对easyUI的介绍:
easyUI就是一个在Jquery的基础上封装了一些组件....我们在编写页面的时候,就可以直接使用这些组件...非常方便...easyUI多用于在后台的页面上...
在学习easyUI之前,我已经学过了bootstrap这么一个前端的框架了...因此学习easyUI并不困难....大多情况下,我们只要查询文档就可以找到对应的答案了。
easyUI快速入门
首先我们得去下载easyUI的资料...
然后在我们把对应的文件导入进去项目中,如下图:
在html文件的body标签内,写上如下的代码:
<!--
第一:写一个普通div标签
第二:提倡为div标签取一个id属性,将来用jquery好定位
第三:为普通div标签添加easyui组件的样式
所有的easyui组件的样式均按如下格式设置:
easyui-组件名
第四:如果要用easyui组件自身的属性时,必须在普通标签上书写data-options属性名,
内容为,key:value,key:value,如果value是string类型加引号,外面双引号,
则里面单引号
注意:要在普通标签中书写data-options属性的前提是:在普通标签上加class="easyui-组件名"
属性值大小写均可
-->
<div
id="xx"
class="easyui-panel"
style="width:500px;height:300px;padding:15px"
title="我的面板"
data-options="iconCls:'icon-save',collapsible:true,minimizable:false,maximizable:true">
这是我的第一个EasyUI程序
</div>
效果:
关于样式的属性我们都会在data-options这个属性上设置的。
除了指定 class="easyui-panel"这样的方式来使用easyUI的组件,我们还可以使用javascript的方式来动态生成...代码如下所示:
<div id="p2" style="padding:10px;">
<p>panel content.</p>
</div>
<script type="text/javascript">
$('#p2').panel({
width: 500,
height: 150,
title: 'My Panel',
border: true,
collapsible: true
});
</script>
在使用easyUI的组件的时候,默认的是英文格式的。如果我们想要变成是中文格式,可以到以下的目录找到对应的JS,在项目中导入进去就行了!
语法
layout布局
layout能够帮助我们布局..
<!-- 布局 -->
<div id="layoutID" style="width:700px;height:500px" class="easyui-layout" data-options="fit:true">
<!-- 区域面板--北边 -->
<div data-options="region:'north',title:'北边',split:true,border:true,iconCls:'icon-remove',collapsible:true" style="height:100px;"></div>
<!-- 区域面板--南边 -->
<div data-options="region:'south',title:'South Title',split:true" style="height:100px;"></div>
<!-- 区域面板--东边 -->
<div data-options="region:'east',iconCls:'icon-reload',title:'East',split:true" style="width:100px;"></div>
<!-- 区域面板--西边 -->
<div data-options="region:'west',title:'West',split:true" style="width:100px;"></div>
<!-- 区域面板--中间 -->
<div data-options="region:'center',title:'中间',href:'/js-day05/images/mm.html'" style="padding:5px;background:#eee;"></div>
</div>
<script type="text/javascript">
//easyui调用方法的语法如下:$('selector').组件名('method',parameter);
//浏览器加载jsp页面时触发
$(function(){
//将北边折叠
$('#layoutID').layout('collapse','north');
//休息3秒
window.setTimeout(function(){
//将南边折叠
$("#layoutID").layout("collapse","south");
//将北边展开
$('#layoutID').layout('expand','north');
window.setTimeout(function(){
//将南边展开
$("#layoutID").layout("expand","south");
},3000);
},3000);
});
</script>
嵌套
当然了,我们的页面不可能只有5个模块,可能还有很多子模块。我们是可以嵌套的。如以下的代码:
<div id="layoutID" class="easyui-layout" data-options="fit:true">
<!-- 北 -->
<div data-options="region:'north'" style="height:100px"></div>
<!-- 中 -->
<div data-options="region:'center'">
<div class="easyui-layout" data-options="fit:true">
<!-- 西 -->
<div data-options="region:'west'" style="width:200px"></div>
<!-- 中 -->
<div data-options="region:'center'">
<div class="easyui-layout" data-options="fit:true">
<!-- 北 -->
<div data-options="region:'north'" style="height:100px"></div>
<!-- 中 -->
<div data-options="region:'center'"></div>
</div>
</div>
</div>
</div>
</div>
accordion分类
<!-- 容器 -->
<div
id="accordionID"
class="easyui-accordion"
data-options="fit:false,border:true,animate:true,multiple:false,selected:-1"
style="width:300px;height:400px;">
<!-- 面板 -->
<div title="标题1" data-options="iconCls:'icon-save'" style="overflow:auto;padding:10px;">
北京
</div>
<div title="标题2" data-options="iconCls:'icon-reload'" style="padding:10px;">
上海
</div>
<div title="标题3">
广州
</div>
<div title="标题4" data-options="collapsible:true">
深圳
</div>
</div>
<script type="text/javascript">
//当浏览器加载web页面时触发
$(function(){
//增加一个面板
//$('selector').plugin('method', parameter);
$("#accordionID").accordion("add",{
"title" : "标题5",
"iconCls" : "icon-add",
"content" : "武汉",
"selected" : false
});
//休息3秒
window.setTimeout(function(){
//移除标题1面板
$("#accordionID").accordion("remove",0);
//取消面板2选中
$("#accordionID").accordion("unselect",0);
//面板3选中
$("#accordionID").accordion("select",1);
},3000);
});
</script>
有格式的按钮linkbutton
<a
id="btn_add"
href="#"
class="easyui-linkbutton"
data-options="iconCls:'icon-add'">增加部门</a><p>
<a
id="btn_find"
href="#"
class="easyui-linkbutton"
data-options="iconCls:'icon-search'">查询部门</a><p>
<a
id="btn_update"
href="#"
class="easyui-linkbutton"
data-options="iconCls:'icon-edit'">修改部门</a><p>
<a
id="btn_delete"
href="#"
class="easyui-linkbutton"
data-options="iconCls:'icon-remove'">删除部门</a><p>
<script type="text/javascript">
//定位4个按钮
$("a").click(function(){
//获取你所单击的按钮的标题
var title = $(this).text();
//去空格
title = $.trim(title);
//显示
alert(title);
});
</script>
选项卡tabs
<!-- 容器 -->
<div
id="tabsID"
class="easyui-tabs"
style="width:500px;height:250px;"
data-options="plain:false,fit:false,border:true,tools:[
{
iconCls:'icon-add',
handler:function(){
alert('添加')
}
},
{
iconCls:'icon-save',
handler:function(){
alert('保存')
}
}
],selected:-1">
<!-- 选项卡 -->
<div title="标题1" style="padding:20px">
tab1<br/>
</div>
<div title="标题2" data-options="closable:true" style="overflow:auto;padding:20px;">
tab2
</div>
<div title="标题3" data-options="iconCls:'icon-reload',closable:true" style="padding:20px;">
tab3
</div>
</div>
分页pagination
<!-- 静态方式创建pagination
<div
id="paginationID"
class="easyui-pagination"
data-options="total:2000,pageSize:10"
style="background:#efefef;border:1px solid #ccc;"></div>
-->
<div
id="paginationID"
style="background:#efefef;border:1px solid #ccc;width:800px">
</div>
<script type="text/javascript">
//total表示总记录数
//pageSize表示每页显示多少条记录
//pageNumber表示当前页号
//pageList表示可供选择的每页显示多少条记录,pageSize变量的值必须属性pageList集合中的值之一
$("#paginationID").pagination({
"total" : 100,
"pageSize" : 10,
"pageNumber" : 1,
"pageList" : [10,20],
"layout" : ['list','sep','first','prev','manual','next','last','links']
});
</script>
<script type="text/javascript">
$("#paginationID").pagination({
"onSelectPage" : function(pageNumber,b){
alert("pageNumber=" + pageNumber);
alert("pageSize=" + b);
}
});
</script>
提示框validatebox
<div style="margin:200px"></div>
姓名:<input id="nameID"/><p/>
<script type="text/javascript">
$("#nameID").validatebox({
required : true,
validType : ['length[1,6]','zhongwen']
});
</script>
<script type="text/javascript">
//自定义规则:zhongwen
$.extend($.fn.validatebox.defaults.rules, {
//zhongwen规则名
zhongwen: {
//validator验证体
//value表示用户在文本框中输入的内容
validator: function(value){
//如果符合中文规则
if(/^[\u3220-\uFA29]*$/.test(value)){
return true;
}
},
//如果不符合中文规则,以下就是提示信息
message: '姓名必须为中文'
}
});
</script>
邮箱:<input id="emailID"/><p/>
<script type="text/javascript">
$("#emailID").validatebox({
required : true,
validType : ['length[1,30]','email']
});
</script>
密码:<input id="passwordID"/><p/>
<script type="text/javascript">
$("#passwordID").validatebox({
required : true,
validType : ['length[6,6]','english']
});
</script>
<script type="text/javascript">
$.extend($.fn.validatebox.defaults.rules, {
english: {
validator: function(value){
if(/^[a-zA-Z]*$/.test(value)){
return true;
}
},
message: '密码必须为英文'
}
});
</script>
ComboBox下拉列表框
<!--
城市:
<select id="cityID" class="easyui-combobox" name="city" style="width:200px;">
<option>aitem1</option>
<option>bitem2</option>
<option>bitem3</option>
<option>citem4</option>
<option>citem5</option>
<option>citem4</option>
<option>ditem5</option>
<option>ditem4</option>
<option>ditem5</option>
<option>ditem4</option>
<option>ditem5</option>
<option>eitem4</option>
<option>eitem5</option>
</select>
-->
城市:
<input id="cityID" name="city"/>
<script type="text/javascript">
//url表示请求的路径
//valueField表示传到服务器的值,看不见的
//textField表示页面中显示的值,看得见
$("#cityID").combobox({
url : "../json/city.json",
valueField :"id",
textField : "name"
});
</script>
<script type="text/javascript">
$(function(){
//为下拉组合框设置值
$("#cityID").combobox("setValue","长沙");
});
</script>
我们的json需要的格式也可以在文档中找到,我们只要对照着来写就行了。
[
{
"id":1,
"name":"北京"
},
{
"id":2,
"name":"上海"
},
{
"id":3,
"name":"广州"
},
{
"id":4,
"name":"深圳"
},
{
"id":5,
"name":"武汉"
}
]
DateBox日期输入框
入职时间:
<input id="dd" type="text"/>
<script type="text/javascript">
$("#dd").datebox({
required : true
});
</script>
<script type="text/javascript">
$("#dd").datebox({
onSelect : function(mydate){
var year = mydate.getFullYear();
var month = mydate.getMonth() + 1;
var date = mydate.getDate();
alert(year+ "年" + month + "月" + date + "日");
}
});
</script>
NumberSpinner数字微调
商品数量:
<input id="ss" style="width:80px;">
<script type="text/javascript">
$("#ss").numberspinner({
min : 1,
max : 100,
value : 1
});
</script>
<p/>
你一共购买了<span id="num">1</span>个商品
<script type="text/javascript">
$("#ss").numberspinner({
onSpinUp : function(){
//获取数字微调的当前值
var value = $("#ss").numberspinner("getValue");
//将当前值设置到span标签中
$("#num").text(value).css("color","red");
},
onSpinDown : function(){
//获取数字微调的当前值
var value = $("#ss").numberspinner("getValue");
//将当前值设置到span标签中
$("#num").text(value).css("color","red");
}
});
</script>
<script type="text/javascript">
$("#ss").keyup(function(xxx){
//将浏览器产生的事件对象设置到myevent变量中
var myevent = xxx;
//获取按键的unicode编码
var code = myevent.keyCode;
//如果按钮是回车
if(code == 13){
//获取数字微调的当前值,因为$(this)此时表示的是文本框,直接获取value属性值即可
var value = $(this).val();
//将当前值设置到span标签中
$("#num").text(value).css("color","red");
}
});
</script>
Slider滑动条
<div style="margin:100px">
身高:<span id="tip"></span>
<p/>
<div id="ss" style="height:400px;width:600px"></div>
</div>
<script type="text/javascript">
$("#ss").slider({
mode : "v",
min : 150,
max : 190,
rule : [ 150,'|',160,'|',170,'|',180,'|',190 ],
showTip : true,
value : 150
});
</script>
<script type="text/javascript">
$("#ss").slider({
onChange : function(newValue){
if(newValue == 160){
$("#tip").text("合格").css("color","blue");
}else if(newValue == 170){
$("#tip").text("良好").css("color","green");
}else if(newValue == 180){
$("#tip").text("优秀").css("color","pink");
}else if(newValue == 190){
$("#tip").text("卓越").css("color","red");
}
}
});
</script>
ProgressBar进度条
<div id="p" style="width:400px;"></div>
<script type="text/javascript">
$("#p").progressbar({
width : 1300,
height : 100,
value : 0
});
</script>
<input id="startID" type="button" value="动起来" style="width:111px;height:111px;font-size:33px"/>
<script type="text/javascript">
//获取1到9之间的随机数,包含1和9
function getNum(){
return Math.floor(Math.random()*9)+1;
}
</script>
<script type="text/javascript">
var timeID = null;
//函数
function update(){
//获取随机值,例如:3
var num = getNum();
//获取进度条当前值,例如:99
var value = $("#p").progressbar("getValue");
//判断
if(value + num > 100){
//强行设置进度条的当前值为100
$("#p").progressbar("setValue",100);
//停止定时器
window.clearInterval(timeID);
//按钮正效
$("#startID").removeAttr("disabled");
}else{
//设置进度条的当前值为num+value的和
$("#p").progressbar("setValue",(value+num));
}
}
//定拉按钮,同时提供单击事件
$("#startID").click(function(){
//每隔300毫秒执行update方法
timeID = window.setInterval("update()",300);
//按钮失效
$(this).attr("disabled","disabled");
});
</script>
Window窗口
<input type="button" value="打开窗口1" id="open1"/>
<input type="button" value="关闭窗口1" id="close1"/>
<div style="margin:600px"></div>
<div id="window1"></div>
<script type="text/javascript">
//定位打开窗口1按钮,同时添加单击事件
$("#open1").click(function(){
//打开窗口1
$("#window1").window({
title : "窗口1",
width : 840,
height : 150,
left : 200,
top : 100,
minimizable : false,
maximizable : false,
collapsible : false,
closable : false,
draggable : false,
resizable : true,
href : "/js-day06/empList.jsp"
});
});
</script>
<script type="text/javascript">
//定位关闭窗口1按钮,同时添加单击事件
$("#close1").click(function(){
//关闭窗口1
$("#window1").window("close");
});
</script>
Dialog对话框窗口
<input type="button" value="打开对话框" id="open"/>
<div style="margin:600px"></div>
<div id="dd"></div>
<script type="text/javascript">
$("#open").click(function(){
$("#dd").dialog({
title : "对话框",
width : 300,
height : 400,
left : 200,
top : 100,
minimizable : false,
maximizable : false,
collapsible : false,
closable : false,
draggable : false,
resizable : true,
toolbar : [
{
text:'编辑',
iconCls:'icon-edit',
handler:function(){alert('edit')}
},
{
text:'帮助',
iconCls:'icon-help',
handler:function(){alert('help')}
}
],
buttons : [
{
text:'提交',
handler:function(){alert("提交");}
},
{
text:'关闭',
handler:function(){
//关闭对话框
$("#dd").dialog("close");
}
}
],
href : "/js-day06/easyui/10_form.html"
});
});
</script>
Messager消息窗口
<input type="button" value="警告框"/><br/>
<input type="button" value="确认框"/><br/>
<input type="button" value="输入框"/><br/>
<input type="button" value="显示框"/><br/>
<div style="margin:100px"></div>
<script type="text/javascript">
//定位所有的button按钮,同时提供单击事件
$(":button").click(function(){
//获取value属性值
var tip = $(this).val();
//去空格
tip = $.trim(tip);
//如果警告框的话
if("警告框" == tip){
$.messager.alert("警告框","继续努力","warning",function(){
alert("关闭");
});
}else if("确认框" == tip){
$.messager.confirm("确认框","你确认要关闭该确认框吗?",function(value){
alert(value);
});
}else if("输入框" == tip){
$.messager.prompt("输入框","你期希的月薪是多少?",function(sal){
if(sal == undefined){
alert("请输入月薪");
}else{
if(sal<6000){
alert("你的谦虚了");
}else if(sal < 7000){
alert("你加点油了");
}else{
alert("你很不错了");
}
}
});
}else if("显示框" == tip){
$.messager.show({
showType : "slide",
showSpeed : 500,
width : 300,
height : 300,
title : "显示框",
msg : "这是内容",
timeout : 5000
});
}
});
</script>
Tree树
<ul id="treeID"></ul>
<script type="text/javascript">
$("#treeID").tree({
url : "/js-day06/json/pro.json"
});
</script>
既然我们用到了JSON,那么我们可以在手册看它需要的格式是什么:
[
{
"id":1,
"text":"广东",
"state":"closed",
"children":[
{
"id":11,
"text":"广州" ,
"state":"closed",
"children":[
{
"id":111,
"text":"天河"
},
{
"id":112,
"text":"越秀"
}
]
},
{
"id":12,
"text":"深圳"
}
]
},
{
"id":2,
"text":"湖南"
}
]
基于easyUI开发的一个综合案例模版
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>练习</title>
<!-- 引入css文件,不限顺序 -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/themes/default/easyui.css" type="text/css"></link>
<link rel="stylesheet" href="${pageContext.request.contextPath}/themes/icon.css" type="text/css"></link>
<!-- 引入js文件,有顺序限制 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.easyui.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/easyui-lang-zh_CN.js"></script>
</head>
<body>
<!-- Layout布局 -->
<div id="layoutID" style="width:700px;height:500px" class="easyui-layout" data-options="fit:true">
<!-- 北 -->
<div data-options="region:'north',border:true,iconCls:'icon-remove',collapsible:true" style="height:100px;">
<center><font style="font-size:66px">jQuery-EasyUI组件</font></center>
</div>
<!-- 南 -->
<div data-options="region:'south'" style="height:100px;">
<center><font style="font-size:33px">XX公司版权所有</font></center>
</div>
<!-- 东 -->
<div data-options="region:'east',iconCls:'icon-reload'" style="width:100px;"></div>
<!-- 西 -->
<div data-options="region:'west'" style="width:200px;">
<!-- Accordion分类 -->
<div
id="accordionID"
class="easyui-accordion"
data-options="fit:true,border:false,selected:-1"
style="width:300px;height:400px;">
<div title="部门管理" data-options="iconCls:'icon-save'" style="padding:10px;">
<!-- Linkbutton按钮 -->
<a
id="btn_add"
href="#"
class="easyui-linkbutton"
data-options="iconCls:'icon-add'">增加部门</a><p>
<a
id="btn_find"
href="#"
class="easyui-linkbutton"
data-options="iconCls:'icon-search'">查询部门</a><p>
<a
id="btn_update"
href="#"
class="easyui-linkbutton"
data-options="iconCls:'icon-edit'">修改部门</a><p>
<a
id="btn_delete"
href="#"
class="easyui-linkbutton"
data-options="iconCls:'icon-remove'">删除部门</a><p>
</div>
<div title="人事管理" data-options="iconCls:'icon-reload'" style="padding:10px;">
<!-- tree树 -->
<ul id="treeID" class="easyui-tree" data-options="lines:true">
<li>
<span>增加人事</span>
</li>
<li>
<span>查询人事</span>
<ul>
<li>
<span>分页查询人事</span>
<ul>
<li>
<span>模糊分页查询人事</span>
</li>
<li>
<span>精确分页查询人事</span>
</li>
</ul>
</li>
<li>
<span>查询所有人事</span>
</li>
</ul>
</li>
</ul>
</div>
<div title="客户管理" data-options="iconCls:'icon-reload'" style="padding:10px;">
客户管理
</div>
<div title="权限管理" data-options="iconCls:'icon-reload'" style="padding:10px;">
权限管理
</div>
<div title="报表管理" data-options="iconCls:'icon-print'" style="padding:10px;">
报表管理
</div>
<div title="帮助" data-options="iconCls:'icon-help'" style="padding:10px;">
帮助
</div>
</div>
</div>
<!-- 中 -->
<div data-options="region:'center'" style="padding:5px;background:#eee;">
<!-- Tabs选项卡 -->
<div
id="tabsID"
class="easyui-tabs"
style="width:500px;height:250px;"
data-options="plain:true,border:false,selected:-1,fit:true">
</div>
</div>
</div>
<script type="text/javascript">
//定位4个按钮
$("a").click(function(){
//获取你所单击的按钮的标题
var title = $(this).text();
//去空格
title = $.trim(title);
//如果title变量是"增加部门"
if("增加部门" == title){
//查看该选项卡是否已经打开
var flag = $("#tabsID").tabs("exists",title);
//如果未打开
if(!flag){
//打开选项卡
$("#tabsID").tabs("add",{
"title" : title,
"closable" : true,
"content" : "文本",
"iconCls" : "icon-add"
});
}
}else if("查询部门" == title){
var flag = $("#tabsID").tabs("exists",title);
if(!flag){
//打开选项卡
$("#tabsID").tabs("add",{
"title" : title,
"closable" : true,
"content" : "文本",
"iconCls" : "icon-search"
});
}
}
});
</script>
<script type="text/javascript">
$(function(){
//收起所有的选项
$("#treeID").tree("collapseAll");
});
</script>
<script type="text/javascript">
$("#treeID").tree({
onClick : function(node){
//获取点击树节点的文本
var title = node.text;
//去空格
title = $.trim(title);
//产生tab选项卡
var flag = $("#tabsID").tabs("exists",title);
//如果没有打开的话
if(!flag){
//打开选项卡
$("#tabsID").tabs("add",{
"title" : title,
"closable" : true,
"href" : "${pageContext.request.contextPath}/empList.jsp",
"iconCls" : "icon-search"
});
}
}
});
</script>
</body>
</html>
效果:
分页
相信我们的分页已经做得不少了,这次我们使用easyUI+Oracle+jdbc来做一个分页...【之前大都都用Mysql,这次用Oracle】
DateGrid会异步以POST方式向服务器传入二个参数:page和rows二个参数,服务端需要哪个,就接收哪个参数
page:需要显示的页号
rows:需要获取多少条记录
编写emp实体
package zhongfucheng.entity;
import java.io.Serializable;
import java.util.Date;
/**
* Created by ozc on 2017/7/17.
*/
public class Emp implements Serializable {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Integer sal;
private Integer comm;
private Integer deptno;
public Emp() {
}
public Emp(Integer empno, String ename, String job, Integer mgr, Date hiredate, Integer sal, Integer comm, Integer deptno) {
this.empno = empno;
this.ename = ename;
this.job = job;
this.mgr = mgr;
this.hiredate = hiredate;
this.sal = sal;
this.comm = comm;
this.deptno = deptno;
}
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Integer getMgr() {
return mgr;
}
public void setMgr(Integer mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Integer getSal() {
return sal;
}
public void setSal(Integer sal) {
this.sal = sal;
}
public Integer getComm() {
return comm;
}
public void setComm(Integer comm) {
this.comm = comm;
}
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
}
编写EmpDao
使用Oracle的语法来实现分页...!
public class EmpDao {
public int getPageRecord() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
String sql = "SELECT COUNT(EMPNO) FROM EMP";
String count = queryRunner.query(sql, new ScalarHandler()).toString();
return Integer.parseInt(count);
}
public List<Emp> getList(int start, int end) throws SQLException {
QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
String sql = "SELECT *FROM (SELECT rownum rownumid,emp.* FROM emp WHERE rownum <= ?) xx WHERE xx.rownumid> ?";
List<Emp> list = (List<Emp>) queryRunner.query(sql, new Object[]{end, start}, new BeanListHandler(Emp.class));
return list;
}
}
编写EmpService
得到对应的分页数据,封装到分页对象中!
public class EmpService {
private EmpDao empDao = new EmpDao();
public Page getPageResult(int currentPage) throws Exception {
Page page = new Page(currentPage, empDao.getPageRecord());
List<Emp> empList = empDao.getList(page.getStartIndex(), page.getLinesize() * currentPage);
page.setList(empList);
return page;
}
}
处理请求的Servlet
接收page参数,如果为空,就设置为1
把得到的分页数据封装成datagrid要的格式,返回给浏览器!
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
try {
//调用service
EmpService empService = new EmpService();
//设置编号方式
request.setCharacterEncoding("UTF-8");
/*获取客户端传递进来的参数,easyUI使用的是page参数*/
String pageStart = request.getParameter("page");
if (pageStart == null || pageStart.length() == 0) {
pageStart = "1";
}
int currentPage = Integer.parseInt(pageStart);
Page pageResult = empService.getPageResult(currentPage);
Map map = new HashMap();
map.put("total", pageResult.getTotalRecord());
map.put("rows", pageResult.getList());
//使用第三方工具将map转成json文本
JSONArray jsonArray = JSONArray.fromObject(map);
String jsonJAVA = jsonArray.toString();
//去掉二边的空格
jsonJAVA = jsonJAVA.substring(1,jsonJAVA.length()-1);
System.out.println("jsonJAVA=" + jsonJAVA);
//以字符流的方式,将json字符串输出到客户端
response.setContentType("text/html;charset=UTF-8");
PrintWriter pw = response.getWriter();
pw.write(jsonJAVA);
pw.flush();
pw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
JSP页面显示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>dataGrid+分页</title>
<link rel="stylesheet" type="text/css" href="easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="easyui/themes/icon.css">
<script type="text/javascript" src="easyui/jquery.min.js"></script>
<script type="text/javascript" src="easyui/jquery.easyui.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/easyui-lang-zh_CN.js"></script>
</head>
<body>
<table id="dg" style="width: 800px" ></table>
<script>
$('#dg').datagrid({
url:'${pageContext.request.contextPath}/getPageServlet?time'+ new Date().getTime(),
columns:[[
/*这里的field要对应JavaBean的属性名称,否则获取不到数据*/
{field:'empno',title:'编号',width:100},
{field:'ename',title:'姓名',width:100},
{field:'job',title:'工作',width:100},
{field:'mgr',title:'上编',width:100},
{field:'hiredate',title:'入时',width:100},
{field:'sal',title:'月薪',width:100},
{field:'comm',title:'佣金',width:100},
{field:'deptno',title:'部编',width:100}
]],
fitColumns : true,
singleSelect : true,
pagination : true,
/*pageSize对应rows,pageNum对应page,datagrid会自动把这两个值传递进去*/
pageNumber : 1,
pageSize : 3,
pageList : [3],
fit:true
});
</script>
</body>
</html>
效果:
BootStrap
BootStrap这个CSS框架是非常火的,现在已经更新到了BootStrap4了,我在个人网站中也有用到它。
它还有其他的组件的,比如:BootStrap-Validation等,用到相关的组件时不妨查查有没有该对应的。
中文教程:http://w3schools.wang/bootstrap/bootstrap_tutorial.html
下面我就截取以慕课网的案例的代码了:
最近在学bootStrap,在慕课网中有这么一个例子....感觉以后会用到这些代码。保存起来。
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>现代浏览器博物馆</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<!--[if lt IE 9]>
<script src="js/html5shiv.js"></script>
<script src="js/respond.min.js"></script>
<![endif]-->
<style>
body {
padding-top: 50px;
padding-bottom: 40px;
color: #5a5a5a;
}
/* 轮播广告 */
.carousel {
height: 500px;
margin-bottom: 60px;
}
.carousel .item {
height: 500px;
background-color: #000;
}
.carousel .item img {
width: 100%;
}
.carousel-caption {
z-index: 10;
}
.carousel-caption p {
margin-bottom: 20px;
font-size: 20px;
line-height: 1.8;
}
/* 简介 */
.summary {
padding-right: 15px;
padding-left: 15px;
}
.summary .col-md-4 {
margin-bottom: 20px;
text-align: center;
}
/* 特性 */
.feature-divider {
margin: 40px 0;
}
.feature {
padding: 30px 0;
}
.feature-heading {
font-size: 50px;
color: #2a6496;
}
.feature-heading .text-muted {
font-size: 28px;
}
/* 响应式布局 */
@media (max-width: 768px) {
.summary {
padding-right: 3px;
padding-left: 3px;
}
.carousel {
height: 300px;
margin-bottom: 30px;
}
.carousel .item {
height: 300px;
}
.carousel img {
min-height: 300px;
}
.carousel-caption p {
font-size: 16px;
line-height: 1.4;
}
.feature-heading {
font-size: 34px;
}
.feature-heading .text-muted {
font-size: 22px;
}
}
@media (min-width: 992px) {
.feature-heading {
margin-top: 120px;
}
}
</style>
</head>
<body>
<!-- 顶部导航 -->
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation" id="menu-nav">
<div class="container">
<div class="navbar-header">
<!--如果分辨率较小,那么这里就会出现-->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">切换导航</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">现代浏览器博物馆</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#ad-carousel">综述</a></li>
<li><a href="#summary-container">简述</a></li>
<!--下拉框-->
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">特点 <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#feature-tab" data-tab="tab-chrome">Chrome</a></li>
<li><a href="#feature-tab" data-tab="tab-firefox">Firefox</a></li>
<li><a href="#feature-tab" data-tab="tab-safari">Safari</a></li>
<li><a href="#feature-tab" data-tab="tab-opera">Opera</a></li>
<li><a href="#feature-tab" data-tab="tab-ie">IE</a></li>
</ul>
</li>
<!--模态窗口-->
<li><a href="#" data-toggle="modal" data-target="#about-modal">关于</a></li>
</ul>
</div>
</div>
</div>
<!-- 广告轮播 -->
<div id="ad-carousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#ad-carousel" data-slide-to="0" class="active"></li>
<li data-target="#ad-carousel" data-slide-to="1"></li>
<li data-target="#ad-carousel" data-slide-to="2"></li>
<li data-target="#ad-carousel" data-slide-to="3"></li>
<li data-target="#ad-carousel" data-slide-to="4"></li>
</ol>
<div class="carousel-inner">
<div class="item active">
<img src="images/chrome-big.jpg" alt="1 slide">
<div class="container">
<div class="carousel-caption">
<h1>Chrome</h1>
<p>Google Chrome,又称Google浏览器,是一个由Google(谷歌)公司开发的网页浏览器。</p>
<p><a class="btn btn-lg btn-primary" href="http://www.google.cn/intl/zh-CN/chrome/browser/"
role="button" target="_blank">点我下载</a></p>
</div>
</div>
</div>
<div class="item">
<img src="images/firefox-big.jpg" alt="2 slide">
<div class="container">
<div class="carousel-caption">
<h1>Firefox</h1>
<p>Mozilla Firefox,中文名通常称为“火狐”或“火狐浏览器”,是一个开源网页浏览器。</p>
<p><a class="btn btn-lg btn-primary" href="http://www.firefox.com.cn/download/" target="_blank"
role="button">点我下载</a></p>
</div>
</div>
</div>
<div class="item">
<img src="images/safari-big.jpg" alt="3 slide">
<div class="container">
<div class="carousel-caption">
<h1>Safari</h1>
<p>Safari,是苹果计算机的最新操作系统Mac OS X中的浏览器。</p>
<p><a class="btn btn-lg btn-primary" href="http://www.apple.com/cn/safari/" target="_blank"
role="button">点我下载</a></p>
</div>
</div>
</div>
<div class="item">
<img src="images/opera-big.jpg" alt="4 slide">
<div class="container">
<div class="carousel-caption">
<h1>Opera</h1>
<p>Opera浏览器,是一款挪威Opera Software ASA公司制作的支持多页面标签式浏览的网络浏览器。</p>
<p><a class="btn btn-lg btn-primary" href="http://www.opera.com/zh-cn" target="_blank"
role="button">点我下载</a></p>
</div>
</div>
</div>
<div class="item">
<img src="images/ie-big.jpg" alt="5 slide">
<div class="container">
<div class="carousel-caption">
<h1>IE</h1>
<p>Internet Explorer,简称 IE,是微软公司推出的一款网页浏览器。</p>
<p><a class="btn btn-lg btn-primary" href="http://ie.microsoft.com/" target="_blank"
role="button">点我下载</a></p>
</div>
</div>
</div>
</div>
<a class="left carousel-control" href="#ad-carousel" data-slide="prev"><span
class="glyphicon glyphicon-chevron-left"></span></a>
<a class="right carousel-control" href="#ad-carousel" data-slide="next"><span
class="glyphicon glyphicon-chevron-right"></span></a>
</div>
<!-- 主要内容 -->
<div class="container summary">
<!-- 简介 -->
<div class="row" id="summary-container">
<div class="col-md-4">
<img class="img-circle" src="images/chrome-logo-small.jpg" alt="chrome">
<h2>Chrome</h2>
<p>Google Chrome,又称Google浏览器,是一个由Google(谷歌)公司开发的网页浏览器。</p>
<p><a class="btn btn-default" href="#" role="button">点我下载</a></p>
</div>
<div class="col-md-4">
<img class="img-circle" src="images/firefox-logo-small.jpg" alt="firefox">
<h2>Firefox</h2>
<p>Mozilla Firefox,中文名通常称为“火狐”或“火狐浏览器”,是一个开源网页浏览器。</p>
<p><a class="btn btn-default" href="#" role="button">点我下载</a></p>
</div>
<div class="col-md-4">
<img class="img-circle" src="images/safari-logo-small.jpg" alt="safari">
<h2>Safari</h2>
<p>Safari,是苹果计算机的最新操作系统Mac OS X中的浏览器。</p>
<p><a class="btn btn-default" href="#" role="button">点我下载</a></p>
</div>
</div>
<!-- 特性 -->
<hr class="feature-divider">
<ul class="nav nav-tabs" role="tablist" id="feature-tab">
<li class="active"><a href="#tab-chrome" role="tab" data-toggle="tab">Chrome</a></li>
<li><a href="#tab-firefox" role="tab" data-toggle="tab">Firefox</a></li>
<li><a href="#tab-safari" role="tab" data-toggle="tab">Safari</a></li>
<li><a href="#tab-opera" role="tab" data-toggle="tab">Opera</a></li>
<li><a href="#tab-ie" role="tab" data-toggle="tab">IE</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab-chrome">
<div class="row feature">
<div class="col-md-7">
<h2 class="feature-heading">Google Chrome <span
class="text-muted">使用最广的浏览器</span></h2>
<p class="lead">Google Chrome,又称Google浏览器,是一个由Google(谷歌)公司开发的网页浏览器。
该浏览器是基于其他开源软件所撰写,包括WebKit,目标是提升稳定性、速度和安全性,并创造出简单且有效率的使用者界面。</p>
</div>
<div class="col-md-5">
<img class="feature-image img-responsive" src="images/chrome-logo.jpg"
alt="Chrome">
</div>
</div>
</div>
<div class="tab-pane" id="tab-firefox">
<div class="row feature">
<div class="col-md-5">
<img class="feature-image img-responsive" src="images/firefox-logo.jpg"
alt="Firefox">
</div>
<div class="col-md-7">
<h2 class="feature-heading">Mozilla Firefox <span class="text-muted">美丽的狐狸</span>
</h2>
<p class="lead">Mozilla Firefox,中文名通常称为“火狐”或“火狐浏览器”,是一个开源网页浏览器,
使用Gecko引擎(非ie内核),支持多种操作系统如Windows、Mac和linux。</p>
</div>
</div>
</div>
<div class="tab-pane" id="tab-safari">
<div class="row feature">
<div class="col-md-7">
<h2 class="feature-heading">Safari <span class="text-muted">Mac用户首选</span></h2>
<p class="lead">Safari,是苹果计算机的最新操作系统Mac OS X中的浏览器,使用了KDE的KHTML作为浏览器的运算核心。
Safari在2003年1月7日首度发行测试版,并成为Mac OS X v10.3与之后的默认浏览器,也是iPhone与IPAD和iPod touch的指定浏览器。</p>
</div>
<div class="col-md-5">
<img class="feature-image img-responsive" src="images/safari-logo.jpg"
alt="Safari">
</div>
</div>
</div>
<div class="tab-pane" id="tab-opera">
<div class="row feature">
<div class="col-md-5">
<img class="feature-image img-responsive" src="images/opera-logo.jpg"
alt="Opera">
</div>
<div class="col-md-7">
<h2 class="feature-heading">Opera <span class="text-muted">小众但易用</span>
</h2>
<p class="lead">Opera浏览器,是一款挪威Opera Software ASA公司制作的支持多页面标签式浏览的网络浏览器。
是跨平台浏览器可以在Windows、Mac和Linux三个操作系统平台上运行。.</p>
</div>
</div>
</div>
<div class="tab-pane" id="tab-ie">
<div class="row feature">
<div class="col-md-7">
<h2 class="feature-heading">IE <span class="text-muted">你懂的</span></h2>
<p class="lead">Internet Explorer,原称Microsoft Internet Explorer(6版本以前)和Windows Internet
Explorer(7,8,9,10版本),
简称IE,是美国微软公司推出的一款网页浏览器。它采用的排版引擎(俗称内核)为Trident。</p>
</div>
<div class="col-md-5">
<img class="feature-image img-responsive" src="images/ie-logo.jpg"
alt="IE">
</div>
</div>
</div>
</div>
<!-- 关于 -->
<div class="modal fade" id="about-modal" tabindex="-1" role="dialog" aria-labelledby="modal-label"
aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span
aria-hidden="true">&times;</span><span class="sr-only">关闭</span></button>
<h4 class="modal-title" id="modal-label">关于</h4>
</div>
<div class="modal-body">
<p>慕课网隶属于北京慕课科技中心(有限合伙),是一家从事互联网免费教学的网络教育公司。秉承“开拓、创新、公平、分享”的精神,
将互联网特性全面的应用在教育领域,致力于为教育机构及求学者打造一站式互动在线教育品牌。</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">了解了</button>
</div>
</div>
</div>
</div>
<!--角标-->
<footer>
<p class="pull-right"><a href="#top">回到顶部</a></p>
<p>&copy; 2014 慕课网 </p>
</footer>
</div>
<script src="js/jquery-1.11.1.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script>
/*触发点击事件*/
$(function () {
$('#ad-carousel').carousel();
$('#menu-nav .navbar-collapse a').click(function (e) {
var href = $(this).attr('href');
var tabId = $(this).attr('data-tab');
if ('#' !== href) {
e.preventDefault();
$(document).scrollTop($(href).offset().top - 70);
if (tabId) {
$('#feature-tab a[href=#' + tabId + ']').tab('show');
}
}
});
});
</script>
</body>
</html>
Bootstrap 模态框避免点击背景处关闭:
解决方法(摘抄自:http://blog.csdn.net/gloomy_114/article/details/51611734):
在HTML页面中编写模态框时,在div初始化时添加属性 aria-hidden=”true” data-backdrop=”static”,即可。。
在需要显示模态框,初始化时,$(‘#myModal’).modal({backdrop: ‘static’, keyboard: false}); 其中 ,backdrop:’static’指的是点击背景空白处不被关闭; keyboard:false指的是触发键盘esc事件时不关闭。
Materialize
这个也是很好看的CSS框架,具体的用法跟BootStrap是差不多的,会了BootStrap这个也就看文档来用了,没什么特别的地方的。
官网:http://materializecss.com
如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y
更多的文章可往:文章的目录导航