vue+iview 实现可编辑表格的示例代码


Posted in Javascript onOctober 31, 2018

先简单说明一下,这个Demo引入的vue,iview的方式是标签引入的,没有用到webpack之类的构建工具...

毕竟公司还在用angularjs+jq.

这也是我第一次写文章,大家看看思路就行了,要是有大佬指点指点就更好了

话不多说,先来个效果图

vue+iview 实现可编辑表格的示例代码

我们再看下极为简单的目录结构

vue+iview 实现可编辑表格的示例代码

IViewEditTable    ## vue+iview 实现的可编辑表格
└── index.html    ## 首页
└── js
 └── editTable.js   ## 首页JS
└── ivew      ## iview相关
└── vue
 ├── axios.min.js   ## axios (ajax)
 ├── util.js    ## 与业务无关的纯工具函数包
 └── vue.min.js   ## vue (2.x)

首页html:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>可编辑表格</title>
 <link href="iview/iview.css" rel="external nofollow" rel="stylesheet" />
</head>
<body style="background-color: #f0f3f4;">
 <div id="editTableCtrl">
 <i-table :loading="loading" border :data="dataList" :columns="columnsList" stripe size="small"></i-table>
 </div>
 <script src="vue/axios.min.js"></script>
 <script src="vue/vue.min.js"></script>
 <script src="iview/iview.min.js"></script>
 <script src="vue/util.js"></script>
 <script src="js/editTable.js"></script>
</body>
</html>

首页没什么说的,都是基本的架子. 这是需要渲染的数据及其说明:

{
 "Status": 1,
 "Total": 233,
 "Items": [{
 "ID": 1,
 "PID": 3,
 "PRJCODE": "2018-001",           //项目编号 不可编辑
 "PRJNAME": "淡化海水配套泵站",         //项目名称 文本输入框
 "PRJTYPE": "基础设施",           //项目类型 下拉选项
 "JSUNIT": "投资公司",           //建设单位 文本输入框
 "FLOW_TYPE_CODE":"A02",           //流程分类 下拉选项,与数据库以code形式交互
 "DATE_START": "2018-12-1",          //开工时间 日期选择
 "DATE_END": "2019-12-1",          //竣工时间 日期选择
 "CONTENT": "建设淡化海水配套泵站一座,占地面积约8500平方米", //建设内容 多行输入框
 "INVEST_ALL": "1000"           //总投资 数字输入框
 }]
}

还有editTable.js的基本架子,$http是我为了方便在utils最后一行加入的 (angularjs用多了,习惯用\$http)

Vue.prototype.utils = utils
window.$http = axios

editTable.js :

var vm = new Vue({
 el: '#editTableCtrl',
 data: function() {
 return {
  loading: true,
  //表格的数据源
  dataList: [],
  // 列
  columnsList: [],
  // 增加编辑状态, 保存状态, 用于操作数据 避免干扰原数据渲染
  cloneDataList: []
 }
 },
 methods: {
 getData: function() {
  var self = this;
  self.loading = true;
  $http.get('json/editTable.txt').then(function(res) {
  self.dataList = res.data.Items;
  self.loading = false;
  });
 },
 },
 created: function() {
 this.getData();
 }
});

我们再来按照iview的规则编写渲染的列:

//...

   /**
    * @name columnsList (浏览器 渲染的列) 
    * @author catkin
    * @see https://www.iviewui.com/components/table
    * @param 
    * { 
    * titleHtml : 渲染带有html的表头 列: '资金<em class="blue" style="color:red">来源</em>'
    * editable : true,可编辑的列 必须有字段 
    * option  : 渲染的下拉框列表,如果需要与数据库交互的值与显示的值不同,须使用[{value:'value',label:'label'}]的形式,下面有例子
    * date   : 渲染成data类型 ,可选参数: 
    *       date | daterange: yyyy-MM-dd (默认)
    *       datetime | datetimerange: yyyy-MM-dd HH:mm:ss
    *       year: yyyy
    *       month: yyyy-MM
    * input   : 渲染input类型 ,可选参数为html5所有类型 (额外增加 textarea 属性), 默认text
    * handle  : 数组类型, 渲染操作方式,目前只支持 'edit', 'delete'
    * }
    * @version 0.0.1
    */

columnsList: [{
  width: 80,
  type: 'index',
  title: '序号',
  align: 'center'
}, {
  align: 'center',
  title: '项目编号',
  key: 'PRJCODE'
}, {
  align: 'center',
  title: '项目名称',
  titleHtml: '项目名称 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'PRJNAME',
  editable: true
}, {
  align: 'center',
  title: '项目分类',
  titleHtml: '项目分类 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'PRJTYPE',
  option: ['产业项目', '基础设施', '民生项目', '住宅项目'],
  editable: true
}, {
  align: 'center',
  title: '建设单位',
  titleHtml: '建设单位 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'JSUNIT',
  editable: true
}, {
  align: 'center',
  title: '流程分类',
  titleHtml: '流程分类 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'FLOW_TYPE_CODE',
  option: [{
   value: 'A01',
   label: '建筑-出让'
  }, {
   value: 'A02',
   label: '建筑-划拨'
  }, {
   value: 'B01',
   label: '市政-绿化'
  }, {
   value: 'B02',
   label: '市政-管线'
  }],
  editable: true
}, {
  align: 'center',
  title: '开工时间',
  titleHtml: '开工时间 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'DATE_START',
  //这里在后面处理的时候会分割成['month','yyyy-MM']的数组,分别代表iview的DatePicker组件选择日期的格式与数据库传过来时页面显示的格式
  date: 'month_yyyy-MM',  
  editable: true
}, {
  align: 'center',
  title: '竣工时间',
  titleHtml: '竣工时间 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'DATE_END',
  date: 'month_yyyy-MM',
  editable: true
}, {
  align: 'center',
  title: '建设内容',
  titleHtml: '建设内容 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'CONTENT',
  input: 'textarea',
  editable: true
}, {
  align: 'center',
  title: '总投资(万元)',
  titleHtml: '总投资<br />(万元) <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'INVEST_ALL',
  input: 'number',
  editable: true
}, {
  title: '操作',
  align: 'center',
  width: 150,
  key: 'handle',
  handle: ['edit', 'delete']
}]

//...

此时页面应该已经可以渲染出表格了

既然要编辑数据,并且我的需求是整行整行的编辑,而编辑的同时就会同步更新数据,那么问题来了
vue中, 数据更新,视图会随之更新. 想象一下,我在输入框中属于一个值,触发了数据更新,接着又触发了视图更新,那么我每次输入时,这个input都会失焦,毫无用户体验. 所以我们把可编辑的动态内容用cloneDataList渲染,静态显示的用dataList渲染
//...
self.dataList = res.data.Items;
// 简单的深拷贝,虽然map会返回新数组,但是数组元素也是引用类型,不能直接改,所以先深拷贝一份
self.cloneDataList = JSON.parse(JSON.stringify(self.dataList)).map(function(item) {
 // 给每行添加一个编辑状态 与 保存状态, 默认都是false
 item.editting = false;
 item.saving = false;
 return item;
});
//...

接下来,我们要根据columnsList做一次循环判断,根据相应的key写出不同的render函数

//全局添加
//根据value值找出数组中的对象元素
function findObjectInOption(value) {
 return function(item) {
 return item.value === value;
 }
}
//动态添加编辑按钮
var editButton = function(vm, h, currentRow, index) {
 return h('Button', {
 props: {
  size: 'small',
  type: currentRow.editting ? 'success' : 'primary',
  loading: currentRow.saving
 },
 style: {
  margin: '0 5px'
 },
 on: {
  click: function() {
  // 点击按钮时改变当前行的编辑状态, 当数据被更新时,render函数会再次执行,详情参考https://cn.vuejs.org/v2/api/#render
  // handleBackdata是用来删除当前行的editting属性与saving属性
  var tempData = vm.handleBackdata(currentRow)
  if (!currentRow.editting) {
   currentRow.editting = true;
  } else {
   // 这里也是简单的点击编辑后的数据与原始数据做对比,一致则不做操作,其实更好的应该遍历所有属性并判断
   if (JSON.stringify(tempData) == JSON.stringify(vm.dataList[index])) {
   console.log('未更改');
   return currentRow.editting = false;
   }
   vm.saveData(currentRow, index)
   currentRow.saving = true;
  }
  }
 }
 }, currentRow.editting ? '保存' : '编辑');
};
//动态添加 删除 按钮
var deleteButton = function(vm, h, currentRow, index) {
 return h('Poptip', {
  props: {
  confirm: true,
  title: currentRow.WRAPDATASTATUS != '删除' ? '您确定要删除这条数据吗?' : '您确定要对条数据撤销删除吗?',
  transfer: true,
  placement: 'left'
  },
  on: {
  'on-ok': function() {
   vm.deleteData(currentRow, index)
  }
  }
 },
 [
  h('Button', {
  style: {
   color: '#ed3f14',
   fontSize: '18px',
   padding: '2px 7px 0',
   border: 'none',
   outline: 'none',
   focus: {
   '-webkit-box-shadow': 'none',
   'box-shadow': 'none'
   }
  },
  domProps: {
   title: '删除'
  },
  props: {
   size: 'small',
   type: 'ghost',
   icon: 'android-delete',
   placement: 'left'
  }
  })
 ]);
};


//methods中添加
init: function() {
 console.log('init');
 var self = this;
 self.columnsList.forEach(function(item) {
 // 使用$set 可以触发视图更新
 // 如果含有titleHtml属性 将其值填入表头
 if (item.titleHtml) {
  self.$set(item, 'renderHeader', function(h, params) {
  return h('span', {
   domProps: {
   innerHTML: params.column.titleHtml
   }
  });
  });
 }
 // 如果含有操作属性 添加相应按钮
 if (item.handle) {
  item.render = function(h, param) {
  var currentRow = self.cloneDataList[param.index];
  var children = [];
  item.handle.forEach(function(item) {
   if (item === 'edit') {
   children.push(editButton(self, h, currentRow, param.index));
   } else if (item === 'delete') {
   children.push(deleteButton(self, h, currentRow, param.index));
   }
  });
  return h('div', children);
  };
 }
 //如果含有editable属性并且为true
 if (item.editable) {
  item.render = function(h, params) {
  var currentRow = self.cloneDataList[params.index];
  // 非编辑状态
  if (!currentRow.editting) {
   // 日期类型单独 渲染(利用工具暴力的formatDate格式化日期)
   if (item.date) {
   return h('span', self.utils.formatDate(currentRow[item.key], item.date.split('_')[1]))
   }
   // 下拉类型中value与label不一致时单独渲染
   if (item.option && self.utils.isArray(item.option)) {
   // 我这里为了简单的判断了第一个元素为object的情况,其实最好用every来判断所有元素
   if (typeof item.option[0] === 'object') {
    return h('span', item.option.find(findObjectInOption(currentRow[item.key])).label);
   }
   }
   return h('span', currentRow[item.key]);
  } else {
  // 编辑状态
   //如果含有option属性
   if (item.option && self.utils.isArray(item.option)) {
   return h('Select', {
    props: {
    // ***重点***: 这里要写currentRow[params.column.key],绑定的是cloneDataList里的数据
    value: currentRow[params.column.key]
    },
    on: {
    'on-change': function(value) {
     self.$set(currentRow, params.column.key, value)
    }
    }
   }, item.option.map(function(item) {
    return h('Option', {
    props: {
     value: item.value || item,
     label: item.label || item
    }
    }, item.label || item);
   }));
   } else if (item.date) {
   //如果含有date属性
   return h('DatePicker', {
    props: {
    type: item.date.split('_')[0] || 'date',
    clearable: false,
    value: currentRow[params.column.key]
    },
    on: {
    'on-change': function(value) {
     self.$set(currentRow, params.column.key, value)
    }
    }
   });
   } else {
   // 默认input
   return h('Input', {
    props: {
    // type类型也是自定的属性
    type: item.input || 'text',
    // rows只有在input 为textarea时才会起作用
    rows: 3,
    value: currentRow[params.column.key]
    },
    on: {
    'on-change'(event) {
     self.$set(currentRow, params.column.key, event.target.value)
    }
    }
   });
   }
  }
  };
 }
 });
},
// 还原数据,用来与原始数据作对比的
handleBackdata: function(object) {
 var clonedData = JSON.parse(JSON.stringify(object));
 delete clonedData.editting;
 delete clonedData.saving;
 return clonedData;
}

到这里完成已经差不多了,补上保存数据与删除数据的函数

// 保存数据
saveData: function(currentRow, index) {
 var self = this;
 // 修改当前的原始数据, 就不需要再从服务端获取了
 this.$set(this.dataList, index, this.handleBackdata(currentRow))
 // 需要保存的数据
 // 模拟ajax
 setTimeout(function() {
 充值编辑与保存状态
 currentRow.saving = false;
 currentRow.editting = false;
 self.$Message.success('保存完成');
 console.log(self.dataList);
 }, 1000)
},
// 删除数据
deleteData: function(currentRow, index) {
 var self = this;
 console.log(currentRow.ID);
 setTimeout(function() {
 self.$delete(self.dataList, index)
 self.$delete(self.cloneDataList, index)
 vm.$Message.success('删除成功');
 }, 1000)
},

完整的editTable.js代码

// 根据数据中下拉的值找到对应的对象
function findObjectInOption(name) {
 return function(item) {
 return item.value === name;
 }
}
var editButton = function(vm, h, currentRow, index) {
 return h('Button', {
 props: {
  size: 'small',
  type: currentRow.editting ? 'success' : 'primary',
  loading: currentRow.saving
 },
 style: {
  margin: '0 5px'
 },
 on: {
  click: function() {
   // 点击按钮时改变当前行的编辑状态,当数据被更新时,render函数会再次执行,详情参考https://cn.vuejs.org/v2/api/#render
   // handleBackdata是用来删除当前行的editting属性与saving属性
   var tempData = vm.handleBackdata(currentRow)
   if (!currentRow.editting) {
   currentRow.editting = true;
   } else {
   // 这里也是简单的点击编辑后的数据与原始数据做对比,一致则不做操作,其实更好的应该遍历所有属性并判断
   if (JSON.stringify(tempData) == JSON.stringify(vm.dataList[index])) {
    console.log('未更改');
    return currentRow.editting = false;
   }
   vm.saveData(currentRow, index)
   currentRow.saving = true;
   }
  }
 }
 }, currentRow.editting ? '保存' : '编辑');
};
//动态添加 删除 按钮
var deleteButton = function(vm, h, currentRow, index) {
 return h('Poptip', {
  props: {
  confirm: true,
  title: currentRow.WRAPDATASTATUS != '删除' ? '您确定要删除这条数据吗?' : '您确定要对条数据撤销删除吗?',
  transfer: true,
  placement: 'left'
  },
  on: {
  'on-ok': function() {
   vm.deleteData(currentRow, index)
  }
  }
 },
 [
  h('Button', {
  style: {
   color: '#ed3f14',
   fontSize: '18px',
   padding: '2px 7px 0',
   border: 'none',
   outline: 'none',
   focus: {
   '-webkit-box-shadow': 'none',
   'box-shadow': 'none'
   }
  },
  domProps: {
   title: '删除'
  },
  props: {
   size: 'small',
   type: 'ghost',
   icon: 'android-delete',
   placement: 'left'
  }
  })
 ]);
};
var vm = new Vue({
 el: '#editTableCtrl',
 data: function() {
 return {
  loading: true,
  //表格的数据源
  dataList: [],
  /**
  * @name columnsList (浏览器 渲染的列) 
  * @author ch
  * @see https://www.iviewui.com/components/table
  * @param 
  * { 
  * titleHtml : 渲染带有html的表头 列: '资金<em class="blue" style="color:red">来源</em>'
  * editable : true,可编辑的列 必须有字段 
  * option : 渲染的下拉框列表
  * date  : 渲染成data类型 ,可选参数: 
  *    date | daterange: yyyy-MM-dd (默认)
  *    datetime | datetimerange: yyyy-MM-dd HH:mm:ss
  *    year: yyyy
  *    month: yyyy-MM
  * input  : 渲染input类型 ,可选参数为html5所有类型 (额外增加 textarea 属性), 默认text
  * handle : 数组类型, 渲染操作方式,目前只支持 'edit', 'delete'
  * }
  * @version 0.0.1
  */
  columnsList: [{
  width: 80,
  type: 'index',
  title: '序号',
  align: 'center'
  }, {
  align: 'center',
  title: '项目编号',
  key: 'PRJCODE'
  }, {
  align: 'center',
  title: '项目名称',
  titleHtml: '项目名称 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'PRJNAME',
  editable: true
  }, {
  align: 'center',
  title: '项目分类',
  titleHtml: '项目分类 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'PRJTYPE',
  option: ['产业项目', '基础设施', '民生项目', '住宅项目'],
  editable: true
  }, {
  align: 'center',
  title: '建设单位',
  titleHtml: '建设单位 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'JSUNIT',
  editable: true
  }, {
  align: 'center',
  title: '流程分类',
  titleHtml: '流程分类 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'FLOW_TYPE_CODE',
  option: [{
   value: 'A01',
   label: '建筑-出让'
  }, {
   value: 'A02',
   label: '建筑-划拨'
  }, {
   value: 'B01',
   label: '市政-绿化'
  }, {
   value: 'B02',
   label: '市政-管线'
  }],
  editable: true
  }, {
  align: 'center',
  title: '开工时间',
  titleHtml: '开工时间 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'DATE_START',
  //这里在后面处理的时候会分割成['month','yyyy-MM']的数组,分别代表iview的DatePicker组件选择日期的格式与数据库传过来时页面显示的格式
  date: 'month_yyyy-MM',
  editable: true
  }, {
  align: 'center',
  title: '竣工时间',
  titleHtml: '竣工时间 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'DATE_END',
  date: 'month_yyyy-MM',
  editable: true
  }, {
  align: 'center',
  title: '建设内容',
  titleHtml: '建设内容 <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'CONTENT',
  input: 'textarea',
  editable: true
  }, {
  align: 'center',
  title: '总投资(万元)',
  titleHtml: '总投资<br />(万元) <i class="ivu-icon ivu-icon-edit"></i>',
  key: 'INVEST_ALL',
  input: 'number',
  editable: true
  }, {
  title: '操作',
  align: 'center',
  width: 150,
  key: 'handle',
  handle: ['edit', 'delete']
  }],
  // 增加编辑状态, 保存状态, 用于操作数据 避免干扰原数据渲染
  cloneDataList: []
 }
 },
 methods: {
 getData: function() {
  var self = this;
  self.loading = true;
  $http.get('json/editTable.txt').then(function(res) {
  // 给每行添加一个编辑状态 与 保存状态
  self.dataList = res.data.Items;
  self.cloneDataList = JSON.parse(JSON.stringify(self.dataList)).map(function(item) {
   item.editting = false;
   item.saving = false;
   return item;
  });
  self.loading = false;
  });
 },
 //初始化数据
 //methods中添加
 init: function() {
  console.log('init');
  var self = this;
  self.columnsList.forEach(function(item) {
  // 使用$set 可以触发视图更新
  // 如果含有titleHtml属性 将其值填入表头
  if (item.titleHtml) {
   self.$set(item, 'renderHeader', function(h, params) {
   return h('span', {
    domProps: {
    innerHTML: params.column.titleHtml
    }
   });
   });
  }
  // 如果含有操作属性 添加相应按钮
  if (item.handle) {
   item.render = function(h, param) {
   var currentRow = self.cloneDataList[param.index];
   var children = [];
   item.handle.forEach(function(item) {
    if (item === 'edit') {
    children.push(editButton(self, h, currentRow, param.index));
    } else if (item === 'delete') {
    children.push(deleteButton(self, h, currentRow, param.index));
    }
   });
   return h('div', children);
   };
  }
  //如果含有editable属性并且为true
  if (item.editable) {
   item.render = function(h, params) {
   var currentRow = self.cloneDataList[params.index];
   // 非编辑状态
   if (!currentRow.editting) {
    // 日期类型单独 渲染(利用工具暴力的formatDate格式化日期)
    if (item.date) {
    return h('span', self.utils.formatDate(currentRow[item.key], item.date.split('_')[1]))
    }
    // 下拉类型中value与label不一致时单独渲染
    if (item.option && self.utils.isArray(item.option)) {
    // 我这里为了简单的判断了第一个元素为object的情况,其实最好用every来判断所有元素
    if (typeof item.option[0] === 'object') {
     return h('span', item.option.find(findObjectInOption(currentRow[item.key])).label);
    }
    }
    return h('span', currentRow[item.key]);
   } else {
    // 编辑状态
    //如果含有option属性
    if (item.option && self.utils.isArray(item.option)) {
    return h('Select', {
     props: {
     // ***重点***: 这里要写currentRow[params.column.key],绑定的是cloneDataList里的数据
     value: currentRow[params.column.key]
     },
     on: {
     'on-change': function(value) {
      self.$set(currentRow, params.column.key, value)
     }
     }
    }, item.option.map(function(item) {
     return h('Option', {
     props: {
      value: item.value || item,
      label: item.label || item
     }
     }, item.label || item);
    }));
    } else if (item.date) {
    //如果含有date属性
    return h('DatePicker', {
     props: {
     type: item.date.split('_')[0] || 'date',
     clearable: false,
     value: currentRow[params.column.key]
     },
     on: {
     'on-change': function(value) {
      self.$set(currentRow, params.column.key, value)
     }
     }
    });
    } else {
    // 默认input
    return h('Input', {
     props: {
     // type类型也是自定的属性
     type: item.input || 'text',
     // rows只有在input 为textarea时才会起作用
     rows: 3,
     value: currentRow[params.column.key]
     },
     on: {
     'on-change'(event) {
      self.$set(currentRow, params.column.key, event.target.value)
     }
     }
    });
    }
   }
   };
  }
  });
 },
 saveData: function(currentRow, index) {
  var self = this;
  // 修改当前的原始数据, 就不需要再从服务端获取了
  this.$set(this.dataList, index, this.handleBackdata(currentRow))
  // 需要保存的数据
  // 模拟ajax
  setTimeout(function() {
  // 重置编辑与保存状态
  currentRow.saving = false;
  currentRow.editting = false;
  self.$Message.success('保存完成');
  console.log(self.dataList);
  }, 1000)
 },
 // 删除数据
 deleteData: function(currentRow, index) {
  var self = this;
  console.log(currentRow.ID);
  setTimeout(function() {
  self.$delete(self.dataList, index)
  self.$delete(self.cloneDataList, index)
  vm.$Message.success('删除成功');
  }, 1000)
 },
 // 还原数据,用来与原始数据作对比的
 handleBackdata: function(object) {
  var clonedData = JSON.parse(JSON.stringify(object));
  delete clonedData.editting;
  delete clonedData.saving;
  return clonedData;
 }
 },
 created: function() {
 this.getData();
 this.init();
 }
});

总结

两三天的时间搞的这些,刚开始也是各种懵逼.期间也试过用插槽来实现,但还是没有这个方法来的清晰(队友都能看懂), 总的来说就是在columnsList自定义一些属性,后面根据这些属性,在render函数里return不同的值,思路还是很简单的.

第一次写文章,并且我也是vue初学者,写的凑合看吧 ^_^ ,欢迎留言指正

本demo 连同之前学习vue时写的demo一起放在的我的github上,欢迎star...

github: https://github.com/catkinmu/vue.js-practice/tree/master/IViewEditTable

参考

vue: render文档
iview
iview admin1.x 版本

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用jquery插件实现图片延迟加载技术详细说明
Mar 12 Javascript
javascript中length属性的探索
Jul 31 Javascript
纯js实现仿QQ邮箱弹出确认框
Apr 29 Javascript
javascript实现完美拖拽效果
May 06 Javascript
javascript表格的渲染组件
Jul 03 Javascript
JS组件Bootstrap实现弹出框和提示框效果代码
Dec 08 Javascript
javascript实现下雪效果【实例代码】
May 03 Javascript
微信小程序 教程之事件
Oct 18 Javascript
AngularJS入门教程之多视图切换用法示例
Nov 02 Javascript
详解在vue-cli中引用jQuery、bootstrap以及使用sass、less编写css
Nov 08 jQuery
Django与Vue语法的冲突问题完美解决方法
Dec 14 Javascript
react的滑动图片验证码组件的示例代码
Feb 27 Javascript
详解vue 项目白屏解决方案
Oct 31 #Javascript
微信小程序ibeacon三点定位详解
Oct 31 #Javascript
小程序获取周围IBeacon设备的方法
Oct 31 #Javascript
详解js删除数组中的指定元素
Oct 31 #Javascript
Vue中使用方法、计算属性或观察者的方法实例详解
Oct 31 #Javascript
Vue项目History模式404问题解决方法
Oct 31 #Javascript
Vue.js中对css的操作(修改)具体方式详解
Oct 30 #Javascript
You might like
PHP默认安装产生系统漏洞
2006/10/09 PHP
Laravel如何使用数据库事务及捕获事务失败后的异常详解
2017/10/23 PHP
PHP使用HTML5 FormData对象提交表单操作示例
2019/07/02 PHP
一个加载js文件的小脚本
2007/06/28 Javascript
Mootools 1.2教程 同时进行多个形变动画
2009/09/15 Javascript
jquery tab标签页的制作
2010/05/10 Javascript
window.onresize 多次触发的解决方法
2013/11/08 Javascript
javascript操作css属性
2013/12/30 Javascript
jquery中$.post()方法的简单实例
2014/02/04 Javascript
jquery实现简单文字提示效果
2015/12/02 Javascript
JS读写CSS样式的方法汇总
2016/08/16 Javascript
jQuery弹出下拉列表插件(实现kindeditor的@功能)
2016/08/16 Javascript
JQuery.validationEngine表单验证插件(推荐)
2016/12/10 Javascript
jQuery实现鼠标悬停3d菜单展开动画效果
2017/01/19 Javascript
简单实现jQuery弹窗效果
2017/10/30 jQuery
vue实现菜单切换功能
2019/05/08 Javascript
vue 使用element-ui中的Notification自定义按钮并实现关闭功能及如何处理多个通知
2019/08/17 Javascript
Python脚本实现集群检测和管理功能
2015/03/06 Python
python使用wmi模块获取windows下硬盘信息的方法
2015/05/15 Python
python使用正则筛选信用卡
2019/01/27 Python
Python 生成一个从0到n个数字的列表4种方法小结
2019/11/28 Python
Python连接Hadoop数据中遇到的各种坑(汇总)
2020/04/14 Python
python下载的库包存放路径
2020/07/27 Python
如何设置PyCharm中的Python代码模版(推荐)
2020/11/20 Python
python爬虫利用selenium实现自动翻页爬取某鱼数据的思路详解
2020/12/22 Python
css图标制作教程制作云图标
2014/01/19 HTML / CSS
美国尼曼百货官网:Neiman Marcus
2019/09/05 全球购物
MIXIT官网:俄罗斯最大的化妆品公司之一
2020/01/25 全球购物
加拿大大码女装购物网站:Penningtons
2020/12/26 全球购物
外贸主管求职简历的自我评价
2013/10/23 职场文书
2014年学生会生活部工作总结
2014/11/07 职场文书
大学生英文求职信范文
2015/03/19 职场文书
趣味运动会标语口号
2015/12/26 职场文书
八年级历史教学反思
2016/02/19 职场文书
Python 文本滚动播放器的实现代码
2021/04/25 Python
python基础之类属性和实例属性
2021/10/24 Python