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 相关文章推荐
PPK 谈 JavaScript 的 this 关键字 [翻译]
Sep 29 Javascript
浅析ajax请求json数据并用js解析(示例分析)
Jul 13 Javascript
Js放到HTML文件中的哪个位置有什么区别
Aug 21 Javascript
js replace(a,b)之替换字符串中所有指定字符的方法
Aug 17 Javascript
jQuery实现最简单的切换图效果【可兼容IE6、火狐、谷歌、opera等】
Sep 04 Javascript
详解js中call与apply关键字的作用
Nov 21 Javascript
详解JavaScript常量定义
Jan 03 Javascript
React Native使用Modal自定义分享界面的示例代码
Oct 31 Javascript
修改node.js默认的npm安装目录实例
May 15 Javascript
vue基础之事件简写、事件对象、冒泡、默认行为、键盘事件实例分析
Mar 11 Javascript
优化Vue中date format的性能详解
Jan 13 Javascript
JavaScript事件的委托(代理)的用法示例详解
Feb 18 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
在PHP3中实现SESSION的功能(一)
2006/10/09 PHP
php中debug_backtrace、debug_print_backtrace和匿名函数用法实例
2014/12/01 PHP
Laravel 5框架学习之向视图传送数据
2015/04/08 PHP
PHP迭代与递归实现无限级分类
2017/08/28 PHP
关于UTF-8的客户端用AJAX方式获取GB2312的服务器端乱码问题的解决办法
2010/11/30 Javascript
使用原生javascript创建通用表单验证——更锋利的使用dom对象
2011/09/13 Javascript
Javascript算符的优先级介绍
2013/03/20 Javascript
全面解析Bootstrap中transition、affix的使用方法
2016/05/30 Javascript
jquery判断iPhone、Android设备类型
2016/09/14 Javascript
Vue通过input筛选数据
2020/10/26 Javascript
详解vue-cli脚手架build目录中的dev-server.js配置文件
2017/11/24 Javascript
微信小程序支付前端源码
2018/08/29 Javascript
Three.js中矩阵和向量的使用教程
2019/03/19 Javascript
微信分享invalid signature签名错误踩过的坑
2020/04/11 Javascript
详解JSON.stringify()的5个秘密特性
2020/05/26 Javascript
[01:30]我们共输赢 完美世界城市挑战赛开启全新赛季
2019/04/19 DOTA
批处理与python代码混合编程的方法
2016/05/19 Python
python按时间排序目录下的文件实现方法
2018/10/17 Python
Python判断以什么结尾以什么开头的实例
2018/10/27 Python
Python函数返回不定数量的值方法
2019/01/22 Python
pyqt5 删除layout中的所有widget方法
2019/06/25 Python
Flask模板引擎之Jinja2语法介绍
2019/06/26 Python
python射线法判断检测点是否位于区域外接矩形内
2019/06/28 Python
妙用itchat! python实现久坐提醒功能
2019/11/25 Python
浅谈Pycharm最有必要改的几个默认设置项
2020/02/14 Python
Python Socket TCP双端聊天功能实现过程详解
2020/06/15 Python
Python类型转换的魔术方法详解
2020/12/23 Python
世界上最值得信赖的多日游在线市场:TourRadar
2018/07/20 全球购物
The Kooples美国官方网站:为情侣提供的法国当代时尚品牌
2019/01/03 全球购物
意大利体育用品和运动服网上商店:Maxi Sport
2019/09/14 全球购物
医学院学生的自我评价分享
2013/11/19 职场文书
小学生元旦感言
2014/02/26 职场文书
《春晓》教学反思
2014/04/20 职场文书
2014年团员学习十八大思想汇报
2014/09/13 职场文书
2016国庆节67周年寄语
2015/12/07 职场文书
PC版《死亡搁浅导剪版》现已发售 展开全新的探险
2022/04/03 其他游戏