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 相关文章推荐
Js动态创建div
Sep 25 Javascript
javascript iframe内的函数调用实现方法
Jul 19 Javascript
一个可以随意添加多个序列的tag函数
Jul 21 Javascript
js的写法基础分析
Jan 17 Javascript
jQuery实现统计复选框选中数量
Nov 24 Javascript
js实现上传图片预览的方法
Feb 09 Javascript
js结合正则实现国内手机号段校验
Jun 19 Javascript
Bootstrap导航条学习使用(二)
Feb 08 Javascript
vue 弹框产生的滚动穿透问题的解决
Sep 21 Javascript
webpack+vue-cli项目中引入外部非模块格式js的方法
Sep 28 Javascript
vue中选项卡点击切换且能滑动切换功能的实现代码
Nov 25 Javascript
ionic4+angular7+cordova上传图片功能的实例代码
Jun 19 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学习之php4与php5之间会穿梭一点点感悟
2007/05/03 PHP
分享PHP函数实现数字与文字分页代码
2015/07/28 PHP
php blowfish加密解密算法
2016/07/02 PHP
PHP get_html_translation_table()函数用法讲解
2019/02/16 PHP
php数组指针函数功能及用法示例
2020/02/11 PHP
web基于浏览器的本地存储方法应用
2012/11/27 Javascript
如何使用json在前后台进行数据传输实例介绍
2013/04/11 Javascript
单击复制文字兼容各浏览器的完美解决方案
2013/07/04 Javascript
jQuery中:nth-child选择器用法实例
2014/12/31 Javascript
基于JavaScript实现微信抢红包功能
2017/07/20 Javascript
Angular2的管道Pipe的使用方法
2017/11/07 Javascript
基于 Immutable.js 实现撤销重做功能的实例代码
2018/03/01 Javascript
nodejs爬虫初试superagent和cheerio
2018/03/05 NodeJs
基于React+Redux的SSR实现方法
2018/07/03 Javascript
Vue用v-for给循环标签自身属性添加属性值的方法
2018/10/18 Javascript
深入理解javascript prototype的相关知识
2019/09/19 Javascript
Echarts实现多条折线可拖拽效果
2019/12/19 Javascript
python对配置文件.ini进行增删改查操作的方法示例
2017/07/28 Python
Python实现桶排序与快速排序算法结合应用示例
2017/11/22 Python
Numpy数据类型转换astype,dtype的方法
2018/06/09 Python
pip命令无法使用的解决方法
2018/06/12 Python
python框架django项目部署相关知识详解
2019/11/04 Python
Python中Subprocess的不同函数解析
2019/12/10 Python
详解pandas赋值失败问题解决
2020/11/29 Python
使用Python下载抖音各大V视频的思路详解
2021/02/06 Python
css3类选择器之结合元素选择器和多类选择器用法
2017/03/09 HTML / CSS
法学函授自我鉴定
2014/02/06 职场文书
毕业自我鉴定书
2014/03/24 职场文书
迎新晚会主持词
2014/03/24 职场文书
安全月活动总结
2014/05/05 职场文书
2014和解协议书范文
2014/09/15 职场文书
综治工作汇报材料
2014/10/27 职场文书
客户经理岗位职责
2015/01/31 职场文书
匿名信格式范文
2015/05/27 职场文书
2016年教师政治思想表现评语
2015/12/02 职场文书
Node与Python 双向通信的实现代码
2021/07/16 Javascript