搭建环境:vue.js+element ui+axios.min.js+xlsx.full.min.js
构建工具:HBuilderX+chrome
下载地址:element ui
编写后台登录界面
HTML代码如下:
这是HTML的代码,可以看得出来,写的不是很好,使用的element提供的组件进行开发,整体使用虚拟DOM 组件功能实现,从布局开始,使用标签
el-container这个标签定义 全局 盒子,然后看自己需要什么样的布局方式 ,可提供的有 el-header头部导航 ,el-main中部身体和el-aside左侧导航,跟el-footer尾部
需要注意的是在Container 中 子元素中有 el-header 或 el-footer 时为 vertical,否则为 horizontal
body{
margin: 0px;
padding: 0px;
background: ;
}
[v-cloak]{
display: none;
}
.el-main{
position: relative;
top:150px;
}
.login-div{
position: fixed;
top: 50%;
left: 50%;
width: 500px;
height: auto;
border: 1px solid skyblue;
transform: translate(-50%,-50%);
border-radius: 20px;
box-shadow: 0 4px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
}
.login-div h4{
text-align: center;
}
.register{
width: 450px;
height: 50px;
margin: auto;
text-align: center;
color: brown;
font-size: 20px;
}
.el-form{
width: 450px;
margin: auto;
}
.form4{
color: #A52A2A;
margin-left: 0px;
}
.form4 a{
float: right;
color: #A52A2A;
text-decoration: none;
}
css样式 主要是对页面 效果做细节调整,虽然没怎么 调好,但是相信小编对div的窗口居中有问题,所以 记录 下来
position: fixed;
top: 50%;
left: 50%;
width: 500px;
height: auto;
border: 1px solid skyblue;
transform: translate(-50%,-50%);
使用固定定位将这个div居中,当然这个只限于整个页面需要展示的只有登录才行,如果小范围div中元素居中就不行了
new Vue({
el:"#app",
data:{
//登录表单
form:{
name:"",
password:"",
code:"",
verify:false,
numbers:0,
},
//忘记密码步骤一表格
forget1:{
name:"",
code:""
},
//更改密码表单
forget2:{
name:"",
password:"",
newpass:""
},
//登录通过
formCode1:true,
//忘记密码验证
formCode2:false,
//重新设置密码
formCode3:false,
//提示语
placeholdermsg:'请输入账号',
//判断密码是否显示
passshow:true,
//判断次数
count:0,
//判断验证码是否显示
show:false,
//按钮信息
codemsg:'发送手机验证码',
//判断是否禁用按钮
isdisabled:false,
//短信按钮定时器
timer:null,
//cookie保存
setCookie:(cname,cvalue,exdays)=>{
var d = new Date();
d.setTime(d.getTime()+(exdays*24*60*60*1000));
var expires = "expires="+d.toGMTString();
document.cookie = cname+"="+cvalue+"; "+expires;
},
//cookie查询
getCookie:(cname)=>{
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name)==0) { return c.substring(name.length,c.length); }
}
return "";
},
},
methods:{
//发送倒计时
send(){
let downTime=60;
if(!this.timer){
this.timer=setInterval(()=>{
if(downTime>0 && downTime<=60){
downTime--;
if(downTime!==0){
this.codemsg="重新发送("+downTime+")";
this.isdisabled=true;
}else{
clearInterval(this.timer);
this.codemsg="发送手机验证码";
downTime=60;
this.timer=null;
this.isdisabled=false;
}
}
},1000)
}
},
//登录表单提交验证
submitForm(form){
let mima='123456';
if(form.password===mima){
this.setCookie('code',"",-1)
/* 测试 */
this.$message('密码正确');
this.setCookie('name',this.form.name,6)
this.setCookie('pass',this.form.password,6)
window.location.href="backstage.html"
}else{
this.count++;
this.$message('密码错误')
this.setCookie('code',this.count,6)
}
let c = this.getCookie('code')
if(c==3){
this.$message('密码错误3次,请使用手机验证码登陆')
this.placeholdermsg='请输入手机号'
this.show=true;
this.passshow=false
}
},
//重置按钮
resetForm(form) {
form.name=''
form.password=''
form.code=''
form.verify=false
this.setCookie('code',"",-1)
},
//记住密码
remenber(isremenber){
if(isremenber){
this.setCookie('name',this.form.name,6)
this.setCookie('pass',this.form.password,6)
}
},
//忘记密码
wangji(){
this.formCode2=true
this.formCode1=false
this.formCode3=false
},
//忘记密码-验证手机验证码
next(msg){
// 验证码接口:通过:ajax
//举例
let data=1234
if(msg.name==null||msg.name==""){
this.$message('手机号码为空')
}else if(msg.code==null||msg.code==""){
this.$message('验证码为空')
}else if(msg.code==data){
this.formCode3=true
this.formCode2=false
this.formCode1=false
}
else{
this.$message('验证码错误')
}
},
last(){
this.formCode3=false
this.formCode2=false
this.formCode1=true
},
//修改密码,成功后返回登录
finish(msg){
// let data=JSON.stringify(msg)
// $.ajax({
// url:"",
// ContextType:{},
// data{
// 数据
// },
// success
// })
//举例
if(msg!=null){
this.formCode3=false
this.formCode2=false
this.formCode1=true
}
}
},
//初始化判断cookie是否有内容,给出提示
created:function(){
//判断输入密码是否超过三次,改用手机号登录
let c = this.getCookie('code')
if(c>=3){
this.show=true;
this.passshow=false;
this.count=c;
this.placeholdermsg='请输入手机号';
}
//判断是否点击保存密码,直接将值赋予input
let name=this.getCookie('name')
let pass=this.getCookie('pass')
if(name!=""&&pass!=""){
this.form.verify=true
this.form.name=name;
this.form.password=pass;
}else{
this.form.verify=false
}
}
})
js采用纯粹的vue方式创建 ,其中涉及到 使用 cookie缓存的记住密码功能,手动编写即可
随后是关于忘记密码的发送定时器
这是登录页面的demo实现效果图
没做太多效果 ,不过没关系,登录界面的主体功能都是有的,当然,没有注册,应该后台登录界面我的设想是后台用户管理中使用权限添加用户
,做完登录后感觉 有点重复造轮子了,很多功能组件可以写成一个个小的功能组件来做的
后台界面这个我是使用的iframe来做路由的,算是路由吧…
那么废话不多说,上代码:
后台管理
XXX医院后台管理系统
员工管理
员工信息管理
员工基本信息
员工权限
病人管理
病人信息管理
病人基本信息
病人离院审核
系统管理
日志信息
背景颜色
消息通知
个人中心
系统设置
退出登录
请在此处放置备案
后端HTML的鸡架子先给它搭好,这样就知道哪里放什么了 ,然后呢,我这里使用了element ui 提供的左侧导航栏可收缩样式,看起来会轻便一些,
输入框本来设想是做一个跳转的,发现没啥页面,就算了,但是依然保留
主要点还是在iframe的使用吧,记住使用时name很重要,它必须跟target标签一致,也就是说,如果你使用a标签跳转,a标签必须添加target属性并且与iframe的name属性一致,好了,看看css样式吧
body{
margin: 0px;
padding: 0px;
}
[v-cloak]{
display: none;
}
.el-menu-vertical-demo{
background: rgb(236,245,255);
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
height: 770px;
}
.demo-type{
height: 60px;
width: 40px;
}
.demo-type span{
margin-top: 11px;
}
.jump_where{
text-decoration: none;
}
从这以后,css就写的少了,主要做一些微调,其它不需要了
那么还是看看我们的js代码吧没啥可说的。
new Vue({
el:'#app2',
data:{
//菜单缩放
isCollapse:false,
//header搜索
state:'',
//搜索下拉列表值
restaurants:[],
},
methods:{
//过滤筛选对应下拉列表值
querySearch(queryString, cb) {
let restaurants = this.restaurants;
let results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
// 调用 callback 返回建议列表的数据
cb(results);
//查询跳转
var newAll=this.loadAll();
document.onkeydown=function(event){
var e = event || window.event || arguments.callee.caller.arguments[0];
if(e&&e.keyCode==13){
var add=''
newAll.filter((item)=>{
if(item.value.indexOf(queryString)!=-1){
add=item.address
}
});
if(add!=null||add==""){
if(add.indexOf(".html")!=-1){
window.location.href=""+add
}
}
}
};
},
//创建过滤器
createFilter(queryString) {
return (restaurant) => {
return (restaurant.value.indexOf(queryString) === 0);
};
},
//点击列表跳转
handleSelect(ev){
console.log(ev.address)
window.location.href=""+ev.address
},
//AJAX传入参数
loadAll(){
return [
{"value": "三全鲜食(北新泾店)","address": "./login.html" },
{"value": "Hot honey 首尔炸鸡(仙霞路)","address": "长宁区北新泾街道天山西路490-1号"},
{"value": "新旺角茶餐厅"},
{"value": "泷千家(天山西路店)"},
{"value": "胖仙女纸杯蛋糕(上海凌空店)"},
{"value": "贡茶"},
];
},
//登录用户系图标下拉列表
selectdrop(e){
console.log(e)
},
//左边导航栏下拉列表
select(e,a){
console.log(e,a)
},
},
//生命周期钩子方法加载页面传递数据到搜索框restaurants中
mounted:function(){
let el=document.querySelector('.el-menu')
let ifarme=document.querySelector('#uiui')
// console.log(ifarme.getAttribute('src'))
console.log(el)
this.restaurants=this.loadAll();
}
})
好吧,感觉也没啥可说的,全是套用的element的组件,简直就是抄的,附上效果图吧,也让大家明白点
当当当当,就是这么个效果,low吧,不过只要实现效果就好,毕竟是练习demo,接下来说一说关于这表格的页面把,其中涉及到axios异步读取json文件,接着是xlsx的导入导出功能实现,来看 代码 吧
HTML照搬一下即可实现一样的效果没啥可以说的,css也一样,根本就没有,那么 直接看js
new Vue({
el:'#app3',
data:{
//查询数据
// search:"",
fullscreenLoading: false,//加载
imfile:'',//导入
outfile:'',//导出
//模拟数据
tableData:[
{'dateTime': '2016-05-02','name': '王小虎','address': '上海市普陀区金沙江路 1518 弄'}
],
//储存选中数据
Selection:[],
//添加数据对话框控件
isaddtab:false,
//添加数据form表单
addform:{
dateTime:'',
name:'',
address:''
},
//更新数据对话框控件
isUpdata:false,
//更新数据表单
updata:{
dateTime:'',
name:'',
address:''
},
//控制更新数据下标
index:''
},
mounted(){
this.imfile=document.getElementById('imFile')
this.outfile=document.getElementById('downlink');
Vue.prototype.$ajax=axios;
this.$ajax.get('./json/file.json').then(res=>{
this.tableData=res.data
})
},
methods:{
//更新按钮
handleEdit(index,row){
// let arr=[]
// this.$ajax.get('./json/file.json').then(res=>{
// arr=res.data
// })
this.isUpdata=true;
this.updata=row
this.index=index
// this.handleEdit(row)
},
//更新表单
handleEditupdata(){
this.updata.dateTime=this.formatDate(this.updata.dateTime)
this.tableData[this.index]=this.updata
this.isUpdata=false;
this.$message({message: '更新成功',type: 'success'});
},
//批量删除
delBates(Selection){
for(let i=0;i<this.tableData.length;i++){
for(let j=0;j<Selection.length;j++){
if(this.tableData[i]==Selection[j]){
this.tableData.splice(i,1)
}
}
}
},
//删除操作
handleDelete(index,row){
row.splice(index, 1);
},
//时间格式
formatDate(date) {
if(date instanceof Date){
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
return y + '-' + m + '-' + d;
}
return date
},
//添加操作
handleEditadd(){
let data=this.addform
if(data.dateTime==null||data.dateTime==""){
this.$message.error('时间不能为空');
}else if(data.name==null||data.name==""){
this.$message.error('名字不能为空');
}else if(data.address==null||data.address==""){
this.$message.error('地址不能为空');
}else{
data.dateTime=this.formatDate(data.dateTime)
this.tableData.push(data)
this.isaddtab=false
this.$message({
message: '添加成功',
type: 'success'
});
this.addform={}
}
},
//获取checkbox选中表全部数据
handleSelectionChange(val){
this.Selection=val
},
//点击导入按钮
uploadFile(){
this.imfile.click()
},
//点击导出按钮
downloadFile(re){
let data=[{}]
for(let key in re[0]){
data[0][key]=key
}
data=data.concat(re)
this.downloadExl(data,"医院信息")
},
//导入操作change事件
importFile() { // 导入excel
this.fullscreenLoading = true
let obj = this.imfile
if (!obj.files) {
this.fullscreenLoading = false
return
}
var f = obj.files[0]
var reader = new FileReader()
let $t = this
reader.onload = function (e) {
var data = e.target.result
if ($t.rABS) {
$t.wb = XLSX.read(btoa(this.fixdata(data)), { // 手动转化
type: 'base64'
})
} else {
$t.wb = XLSX.read(data, {
type: 'binary'
})
}
let json = XLSX.utils.sheet_to_json($t.wb.Sheets[$t.wb.SheetNames[0]])
// console.log(typeof json)
$t.dealFile($t.analyzeData(json)) // analyzeData: 解析导入数据
}
if (this.rABS) {
reader.readAsArrayBuffer(f)
} else {
reader.readAsBinaryString(f)
}
},
//导出操作引用事件具体实现
downloadExl(json, downName, type) {// 导出到excel
let keyMap = [] // 获取键
for (let k in json[0]) {
keyMap.push(k)
}
// console.info('keyMap', keyMap, json)
let tmpdata = [] // 用来保存转换好的json
json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
v: v[k],
position: (j > 25 ? this.getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
}))).reduce((prev, next) => prev.concat(next)).forEach(function (v) {
tmpdata[v.position] = {
v: v.v
}
})
//替换字符串
for(let key in tmpdata){
if(tmpdata[key].v=='dateTime'){
tmpdata[key].v='日期'
}else if(tmpdata[key].v=='name'){
tmpdata[key].v='名字'
}else if(tmpdata[key].v=='address'){
tmpdata[key].v='地址'
}
}
let outputPos = Object.keys(tmpdata) // 设置区域,比如表格从A1到D10
let tmpWB = {
SheetNames: ['mySheet'], // 保存的表标题
Sheets: {
'mySheet': Object.assign({},
tmpdata, // 内容
{
'!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1] // 设置填充区域
})
}
}
let tmpDown = new Blob([this.s2ab(XLSX.write(tmpWB,
{bookType: (type === undefined ? 'xlsx' : type), bookSST: false, type: 'binary'} // 这里的数据是用来定义导出的格式类型
))], {
type: ''
}) // 创建二进制对象写入转换好的字节流
var href = URL.createObjectURL(tmpDown) // 创建对象超链接
this.outfile.download = downName + '.xlsx' // 下载名称
this.outfile.href = href // 绑定a标签
this.outfile.click() // 模拟点击实现下载
setTimeout(function () { // 延时释放
URL.revokeObjectURL(tmpDown) // 用URL.revokeObjectURL()来释放这个object URL
}, 100)
},
analyzeData(data) { // 此处可以解析导入数据
return data
},
dealFile(data) { // 处理导入的数据
// console.log(data[0])
//替换表头
let newdata=[]
for(let i=0;i<data.length;i++){
let json1 = JSON.parse(JSON.stringify(data[i]).replace(/日期/g,"dateTime"));
let json2 = JSON.parse(JSON.stringify(json1).replace(/名字/g,"name"));
let json3 = JSON.parse(JSON.stringify(json2).replace(/地址/g,"address"));
newdata.push(json3)
}
this.imfile.value = ''
this.fullscreenLoading = false
if (newdata.length <= 0) {
this.$message.error('请导入正确信息');
} else {
this.$message({
message: '导入成功',
type: 'success'
});
this.tableData = newdata
}
},
s2ab(s) { // 字符串转字符流
var buf = new ArrayBuffer(s.length)
var view = new Uint8Array(buf)
for (var i = 0; i !== s.length; ++i) {
view[i] = s.charCodeAt(i) & 0xFF
}
return buf
},
getCharCol(n) { // 将指定的自然数转换为26进制表示。映射关系:[0-25] -> [A-Z]。
let s = ''
let m = 0
while (n > 0) {
m = n % 26 + 1
s = String.fromCharCode(m + 64) + s
n = (n - m) / 26
}
return s
},
fixdata(data) { // 文件流转BinaryString
var o = ''
var l = 0
var w = 10240
for (; l < data.byteLength / w; ++l) {
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
}
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
return o
}
},
})
内容可丰富了,主要讲讲关于axios和xlsx的使用吧 ,axios我是直接赋值给了vue实例原型创建的$ajax上的
mounted(){
this.imfile=document.getElementById('imFile')
this.outfile=document.getElementById('downlink');
Vue.prototype.$ajax=axios;
this.$ajax.get('./json/file.json').then(res=>{
this.tableData=res.data
})
},
那么,然后就是关于methods的一些方法了,主要说xlsx的使用吧,由于导入导出需要我直接从网上拷了一套使用方式
//导入操作change事件
importFile() { // 导入excel
this.fullscreenLoading = true
let obj = this.imfile
if (!obj.files) {
this.fullscreenLoading = false
return
}
var f = obj.files[0]
var reader = new FileReader()
let $t = this
reader.onload = function (e) {
var data = e.target.result
if ($t.rABS) {
$t.wb = XLSX.read(btoa(this.fixdata(data)), { // 手动转化
type: 'base64'
})
} else {
$t.wb = XLSX.read(data, {
type: 'binary'
})
}
let json = XLSX.utils.sheet_to_json($t.wb.Sheets[$t.wb.SheetNames[0]])
// console.log(typeof json)
$t.dealFile($t.analyzeData(json)) // analyzeData: 解析导入数据
}
if (this.rABS) {
reader.readAsArrayBuffer(f)
} else {
reader.readAsBinaryString(f)
}
},
//导出操作引用事件具体实现
downloadExl(json, downName, type) {// 导出到excel
let keyMap = [] // 获取键
for (let k in json[0]) {
keyMap.push(k)
}
// console.info('keyMap', keyMap, json)
let tmpdata = [] // 用来保存转换好的json
json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
v: v[k],
position: (j > 25 ? this.getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
}))).reduce((prev, next) => prev.concat(next)).forEach(function (v) {
tmpdata[v.position] = {
v: v.v
}
})
//替换字符串
for(let key in tmpdata){
if(tmpdata[key].v=='dateTime'){
tmpdata[key].v='日期'
}else if(tmpdata[key].v=='name'){
tmpdata[key].v='名字'
}else if(tmpdata[key].v=='address'){
tmpdata[key].v='地址'
}
}
let outputPos = Object.keys(tmpdata) // 设置区域,比如表格从A1到D10
let tmpWB = {
SheetNames: ['mySheet'], // 保存的表标题
Sheets: {
'mySheet': Object.assign({},
tmpdata, // 内容
{
'!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1] // 设置填充区域
})
}
}
let tmpDown = new Blob([this.s2ab(XLSX.write(tmpWB,
{bookType: (type === undefined ? 'xlsx' : type), bookSST: false, type: 'binary'} // 这里的数据是用来定义导出的格式类型
))], {
type: ''
}) // 创建二进制对象写入转换好的字节流
var href = URL.createObjectURL(tmpDown) // 创建对象超链接
this.outfile.download = downName + '.xlsx' // 下载名称
this.outfile.href = href // 绑定a标签
this.outfile.click() // 模拟点击实现下载
setTimeout(function () { // 延时释放
URL.revokeObjectURL(tmpDown) // 用URL.revokeObjectURL()来释放这个object URL
}, 100)
},
analyzeData(data) { // 此处可以解析导入数据
return data
},
dealFile(data) { // 处理导入的数据
// console.log(data[0])
//替换表头
let newdata=[]
for(let i=0;i<data.length;i++){
let json1 = JSON.parse(JSON.stringify(data[i]).replace(/日期/g,"dateTime"));
let json2 = JSON.parse(JSON.stringify(json1).replace(/名字/g,"name"));
let json3 = JSON.parse(JSON.stringify(json2).replace(/地址/g,"address"));
newdata.push(json3)
}
this.imfile.value = ''
this.fullscreenLoading = false
if (newdata.length <= 0) {
this.$message.error('请导入正确信息');
} else {
this.$message({
message: '导入成功',
type: 'success'
});
this.tableData = newdata
}
},
s2ab(s) { // 字符串转字符流
var buf = new ArrayBuffer(s.length)
var view = new Uint8Array(buf)
for (var i = 0; i !== s.length; ++i) {
view[i] = s.charCodeAt(i) & 0xFF
}
return buf
},
getCharCol(n) { // 将指定的自然数转换为26进制表示。映射关系:[0-25] -> [A-Z]。
let s = ''
let m = 0
while (n > 0) {
m = n % 26 + 1
s = String.fromCharCode(m + 64) + s
n = (n - m) / 26
}
return s
},
fixdata(data) { // 文件流转BinaryString
var o = ''
var l = 0
var w = 10240
for (; l < data.byteLength / w; ++l) {
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
}
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
return o
}
},
当然也有一些自己改的地方,比如,导入导出会出现表头如果是英文那么,导入会是英文,而我的数据是需要中文表头的,所以导入我给 替换了一下
let newdata=[]
for(let i=0;i<data.length;i++){
let json1 = JSON.parse(JSON.stringify(data[i]).replace(/日期/g,"dateTime"));
let json2 = JSON.parse(JSON.stringify(json1).replace(/名字/g,"name"));
let json3 = JSON.parse(JSON.stringify(json2).replace(/地址/g,"address"));
newdata.push(json3)
}
导出也一样
//替换字符串
for(let key in tmpdata){
if(tmpdata[key].v=='dateTime'){
tmpdata[key].v='日期'
}else if(tmpdata[key].v=='name'){
tmpdata[key].v='名字'
}else if(tmpdata[key].v=='address'){
tmpdata[key].v='地址'
}
}
这样就可以保障导入不会出现数据key不对称啊,导出表头为英文啊这种问题了
好了 ,就说这么多,持续踩坑中哦
www.gzsdkt.com ,没别的意思,就是推广一下网站,欢迎广州地区有需要中央空调的同志们来本站看看