vue2+element实现Table表格嵌套输入框、选择器、日期选择器、表单弹出窗组件的行内编辑功能

vue2+element实现Table表格嵌套输入框、选择器、日期选择器、表单弹出窗组件的行内编辑功能


文章目录

  • vue2+element实现Table表格嵌套输入框、选择器、日期选择器、表单弹出窗组件的行内编辑功能
  • 前言
  • 一、准备工作
  • 二、行内编辑
    • 1.嵌入Input文本输入框
      • 1.1遇到问题
        • 1.文本框内容修改失去焦点后,editLoading也设置为false了,但是加载动画一直在转
    • 2.嵌入Select选择器
    • 3.嵌入DatePicker日期选择器
      • 3.1遇到问题
        • 1.表格的数据日期格式是时间戳格式,需要将时间戳转化为常见‘年-月-日’格式
    • 4.嵌入表单弹出框组件
      • 4.1遇到问题
        • 1.手动激活模式下的弹窗显示和关闭的问题
        • 2.表单的验证功能显示不正常
  • 三、总结


前言

提示:本文的开发环境是vue2+element UI2.13.2

最近自己的项目需要使用到表格的行内编辑功能,主要是在表格中集成输入框、弹出窗(表单组件)、选择框、时间选择框等组件,实现表格行内的编辑。
在这里插入图片描述


一、准备工作

首先不管表格嵌入什么组件,我们都要对表格的单元格进行索引标记这一准备工作,这样的话我们就可以知道我们点击的是哪一行哪一列的单元格了,我这里利用的是element UI里table自带的属性:row-class-name和cell-class-name,

同时在vue的data中设置另个数据:rowIndex: -1, columnIndex: -1,用来表示当前点击索引坐标。

之后创建一个表格单元格点击事件handleCellClick,输出点击单元格的坐标,坐标索引正确,则说明准备工作完毕,可以加入编辑组件了。准备工作代码如下:

提示:本文的目的是分享行内编辑实现过程,文中存在大量代码示例,读者可自行选择合适的代码进行复制粘贴,然后微调实现自己想要的功能,文章最后附有标题中所有组件的完整代码。

<template><div class="app-container"><el-table :data="tableData" border style="width: 800px;" :row-class-name="tableRowIndex" :cell-class-name="tableCellIndex" @cell-click="handleCellClick"><el-table-column fixed prop="date" label="日期" width="150" /><el-table-column prop="name" label="姓名" width="120" /><el-table-column prop="province" label="省份" width="120" /><el-table-column prop="city" label="市区" width="120" /><el-table-column prop="address" label="地址" width="300" /><el-table-column prop="zip" label="邮编" width="120" /><el-table-column fixed="right" label="操作" width="100"><template slot-scope="scope"><el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button><el-button type="text" size="small">编辑</el-button></template></el-table-column></el-table></div>
</template><script>
export default {name: 'Testdemo',data() {return {tableData: [{ id: 1, date: '2016-05-02', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1518 弄', zip: 200333 },{ id: 2, date: '2016-05-04', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1517 弄', zip: 200333 },{ id: 3, date: '2016-05-01', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1519 弄', zip: 200333 },{ id: 4, date: '2016-05-03', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1516 弄', zip: 200333 }],// 表格行内编辑相关属性rowIndex: -1, // 行索引columnIndex: -1 // 列索引}},// 监听属性computed: {},// 生命周期mounted() {},created() {},// 方法methods: {handleClick(row) {console.log(row)},// 行内编辑相关基础方法// 把每一行的索引加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格tableRowIndex({ row, rowIndex }) {// console.log(rowIndex)// 初始化行数据,将索引添加到行数据中row.index = rowIndex},// 把每一列的索引加到列数据中tableCellIndex({ column, columnIndex }) {// 初始化行数据,将索引添加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格column.index = columnIndex},/** 表格点击事件 */handleCellClick(row, column, cell, event) {this.rowIndex = row.indexthis.columnIndex = column.indexconsole.log('rowIndex', this.rowIndex)console.log('columnIndex', this.columnIndex)}}
}
</script>
<style lang="scss" scoped></style>

二、行内编辑

1.嵌入Input文本输入框

点击‘编辑’图标,则可激活文本输入框对名字进行编辑修改,实现效果如图:
在这里插入图片描述

在准备工作的代码中继续完善代码。在data属性中添加iputIndex: -1 ,表示输入框索引。

data() {return {...iputIndex: -1 // 输入框索引}},

编写显示文本框的方法inputShow()

// 显示输入框inputShow(scope) {this.iputIndex = scope.row.indexthis.rowIndex = scope.row.indexthis.columnIndex = scope.column.index},

当输入框显示之后,我们可以对其文本进行编辑和修改,也就是说文本框是获取焦点状态,当它失去焦点的时候,我们默认文本框不显示并且提交修改过的文本到后台。
定义编辑文本方法editName()

// 输入框编辑名字editName(row) {this.iputIndex = -1this.rowIndex = -1this.columnIndex = -1row.editLoading = truesetTimeout(function() {// 使用替换整个对象而不是修改其属性也是一个解决方案。这可以确保 Vue 检测到变化并更新视图row.editLoading = falsethis.$set(this.tableData, row.index, row)console.log('失去焦点', this.tableData)}.bind(this), 1000)}

在DOM中根据 scope.row.index == iputIndex &&scope.column.index == columnIndex && scope.row.index == rowIndex,当点击单元格的索引坐标和数据的索引坐标都一样的时候,显示对应的文本输入框。

...<el-table-column prop="name" label="姓名" width="120"><template slot-scope="scope"><template v-if="scope.row.index == iputIndex && scope.column.index == columnIndex && scope.row.index == rowIndex"><el-input:ref="'sortNumRef' + scope.row.id"v-model="scope.row.name"size="small"autofocus="true"@blur="editName(scope.row)"/></template><template v-if="scope.row.editLoading"><i class="el-icon-loading" /></template><template v-if="scope.row.index != iputIndex && !scope.row.editLoading"><span>{{ scope.row.name }}</span><el-button type="text" icon="el-icon-edit" style="margin-left: 10px" @click="inputShow(scope)" /></template></template></el-table-column>...

同时我们也需要在表格外的div绑定一个方法,当鼠标点击表格外区域时不显示文本输入框,定义handleClickOutside方法。

/** 监听鼠标点击表格外面区域的时候,行内编辑失去焦点*/handleClickOutside(event) {var isTargetOrChild = event.target.classNameif (isTargetOrChild !== '' &&isTargetOrChild !== 'el-icon-edit' &&isTargetOrChild !== 'el-input__inner') {this.rowIndex = -1this.columnIndex = -1this.iputIndex = -1 // 此处解决点击方框极近处}},

到此,我们就实现了Table嵌入Input文本输入框,完整代码如下:

<template><div class="app-container" @click="handleClickOutside"><el-table :data="tableData" border style="width: 800px;" :row-class-name="tableRowIndex" :cell-class-name="tableCellIndex" @cell-click="handleCellClick"><el-table-column fixed prop="date" label="日期" width="150" /><el-table-column prop="name" label="姓名" width="120"><template slot-scope="scope"><template v-if="scope.row.index == iputIndex && scope.column.index == columnIndex && scope.row.index == rowIndex"><el-input:ref="'sortNumRef' + scope.row.id"v-model="scope.row.name"size="small"autofocus="true"@blur="editName(scope.row)"/></template><template v-if="scope.row.editLoading"><i class="el-icon-loading" /></template><template v-if="scope.row.index != iputIndex && !scope.row.editLoading"><span>{{ scope.row.name }}</span><el-button type="text" icon="el-icon-edit" style="margin-left: 10px" @click="inputShow(scope)" /></template></template></el-table-column><el-table-column prop="province" label="省份" width="120" /><el-table-column prop="city" label="市区" width="120" /><el-table-column prop="address" label="地址" width="300" /><el-table-column prop="zip" label="邮编" width="120" /><el-table-column fixed="right" label="操作" width="100"><template slot-scope="scope"><el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button><el-button type="text" size="small">编辑</el-button></template></el-table-column></el-table></div>
</template><script>
export default {name: 'Testdemo',data() {return {tableData: [{ id: 1, date: '2016-05-02', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1518 弄', zip: 200333 },{ id: 2, date: '2016-05-04', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1517 弄', zip: 200333 },{ id: 3, date: '2016-05-01', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1519 弄', zip: 200333 },{ id: 4, date: '2016-05-03', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1516 弄', zip: 200333 }],// 表格行内编辑相关属性rowIndex: -1, // 行索引columnIndex: -1, // 列索引iputIndex: -1 // 输入框索引}},// 监听属性computed: {},// 生命周期mounted() {},created() {},// 方法methods: {handleClick(row) {console.log(row)},// 行内编辑相关基础方法// 把每一行的索引加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格tableRowIndex({ row, rowIndex }) {// console.log(rowIndex)// 初始化行数据,将索引添加到行数据中row.index = rowIndex},// 把每一列的索引加到列数据中tableCellIndex({ column, columnIndex }) {// 初始化行数据,将索引添加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格column.index = columnIndex},/** 表格点击事件 */handleCellClick(row, column, cell, event) {this.rowIndex = row.indexthis.columnIndex = column.index},/** 监听鼠标点击表格外面区域的时候,行内编辑失去焦点*/handleClickOutside(event) {var isTargetOrChild = event.target.classNameif (isTargetOrChild !== '' &&isTargetOrChild !== 'el-icon-edit' &&isTargetOrChild !== 'el-input__inner') {this.rowIndex = -1this.columnIndex = -1this.iputIndex = -1 // 此处解决点击方框极近处}},// 显示输入框inputShow(scope) {this.iputIndex = scope.row.indexthis.rowIndex = scope.row.indexthis.columnIndex = scope.column.index},// 输入框编辑名字editName(row) {this.iputIndex = -1this.rowIndex = -1this.columnIndex = -1row.editLoading = truesetTimeout(function() {// 使用替换整个对象而不是修改其属性也是一个解决方案。这可以确保 Vue 检测到变化并更新视图/* const updatedRow = { ...row, editLoading: false }this.tableData.splice(this.tableData.indexOf(row), 1, updatedRow) */row.editLoading = falsethis.$set(this.tableData, row.index, row)// console.log('失去焦点', this.tableData)}.bind(this), 1000)}}
}
</script><style lang="scss" scoped></style>

1.1遇到问题

1.文本框内容修改失去焦点后,editLoading也设置为false了,但是加载动画一直在转

在 Vue 中,当你直接修改对象数组中的某个对象的属性时,Vue 可能无法检测到这个变化,因此不会触发视图>更新。这是因为 Vue 使用的是“响应式系统”来追踪数据的变化,但它只能检测到对象属性的添加或删除,或者>>数组元素的添加、删除或顺序改变。对于数组或对象内部属性的直接修改(如 array[index] = newValue 或 >object.property = newValue),Vue 可能无法检测到变化。解决办法:vue 提供了一个 Vue.set 方法(在 Vue 3 中是 this.$set)

this.$set(this.tableData, row.index, row)

2.嵌入Select选择器

在嵌入文本输入框的基础上再加入select下拉选择框,效果如下:
在这里插入图片描述
在data属性中添加两个数据,一个是select下拉框的选项数组optionsList,一个是用来保存原始数据的变量originalData,当修改的数据和原始数据不一致的情况下才进行提交数据和刷新表格。

data() {return {.../* --------------------------下拉框相关属性-------------------------- */optionsList: [{ id: 1, name: '上海' },{ id: 2, name: '重庆' },{ id: 3, name: '北京' }],// 原始数据,用来和修改的数据进行对比,有变化才能提交数据,否则不提交。originalData: null}...},

还需要在表格点击事件方法handleCellClick中,对originalData变量赋值。

handleCellClick(row, column, cell, event) {...var ifproperty = Object.prototype.hasOwnProperty.call(column, 'property')if (ifproperty) {const property = column.propertyif (property === 'province') { //判断是否是省份那一列this.$nextTick(() => {this.$refs['sortNum' + row.id].focus()this.originalData = Array.from(row.province)// console.log('原始数据', this.originalData)})}}},

我们还需要用到select选择框的blur、visible-change、remove-tag和change事件。
在这里插入图片描述

在DOM中根据 scope.row.index == iputIndex &&scope.column.index == columnIndex,当点击单元格的索引坐标和数据的索引坐标都一样的时候,显示对应的下拉选择框。完整代码如下:

<template><div class="app-container" @click="handleClickOutside"><el-table :data="tableData" border style="width: 800px;" :row-class-name="tableRowIndex" :cell-class-name="tableCellIndex" @cell-click="handleCellClick"><el-table-column fixed prop="date" label="日期" width="150" /><el-table-column prop="name" label="姓名" width="120"><template slot-scope="scope"><template v-if="scope.row.index == iputIndex && scope.column.index == columnIndex && scope.row.index == rowIndex"><el-input:ref="'sortNumRef' + scope.row.id"v-model="scope.row.name"size="small"autofocus="true"@blur="inputEditName(scope.row)"/></template><template v-if="scope.row.editLoading"><i class="el-icon-loading" /></template><template v-if="scope.row.index != iputIndex && !scope.row.editLoading"><span>{{ scope.row.name }}</span><el-button type="text" icon="el-icon-edit" style="margin-left: 10px" @click="inputShow(scope)" /></template></template></el-table-column><el-table-column prop="province" label="省份" width="200"><template slot-scope="scope"><el-selectv-if="rowIndex === scope.row.index && columnIndex === scope.column.index":ref="'sortNum' + scope.row.id"v-model="scope.row.province"style="width: 100%"size="small"filterablemultipleplaceholder="请选择"@blur="selectBlur"@visible-change="selectVisibleChange"@remove-tag="selectTagClose(scope.row.province,scope.row)"@change="selectChange(scope.row.province,scope.row)"><el-option v-for="item in optionsList" :key="item.id" :label="item.name" :value="item.id" /></el-select><span v-else style="cursor: pointer;">{{ Array.isArray(scope.row.province_name)? scope.row.province_name.join(","): "" }}</span></template></el-table-column><el-table-column prop="city" label="市区" width="120" /><el-table-column prop="address" label="地址" width="300" /><el-table-column prop="zip" label="邮编" width="120" /><el-table-column fixed="right" label="操作" width="100"><template slot-scope="scope"><el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button><el-button type="text" size="small">编辑</el-button></template></el-table-column></el-table></div>
</template><script>
export default {name: 'Testdemo',data() {return {tableData: [{ id: 1, date: '2016-05-02', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1518 弄', zip: 200333 },{ id: 2, date: '2016-05-04', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1517 弄', zip: 200333 },{ id: 3, date: '2016-05-01', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1519 弄', zip: 200333 },{ id: 4, date: '2016-05-03', name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', address: '上海市普陀区金沙江路 1516 弄', zip: 200333 }],// 表格行内编辑相关属性rowIndex: -1, // 行索引columnIndex: -1, // 列索引/* --------------------------输入框相关属性-------------------------- */iputIndex: -1, // 输入框索引/* --------------------------下拉框相关属性-------------------------- */optionsList: [{ id: 1, name: '上海' },{ id: 2, name: '重庆' },{ id: 3, name: '北京' }],// 原始数据,用来和修改的数据进行对比,有变化才能提交数据,否则不提交。originalData: null}},// 监听属性computed: {},// 生命周期mounted() {},created() {},// 方法methods: {handleClick(row) {console.log(row)},/* --------------------------行内编辑相关基础方法-------------------------- */// 把每一行的索引加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格tableRowIndex({ row, rowIndex }) {// console.log(rowIndex)// 初始化行数据,将索引添加到行数据中row.index = rowIndex},// 把每一列的索引加到列数据中tableCellIndex({ column, columnIndex }) {// 初始化行数据,将索引添加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格column.index = columnIndex},// 表格点击事件handleCellClick(row, column, cell, event) {this.rowIndex = row.indexthis.columnIndex = column.indexvar ifproperty = Object.prototype.hasOwnProperty.call(column, 'property')if (ifproperty) {const property = column.propertyif (property === 'province') {this.$nextTick(() => {this.$refs['sortNum' + row.id].focus()this.originalData = Array.from(row.province)// console.log('原始数据', this.originalData)})}}},// 监听鼠标点击表格外面区域的时候,行内编辑失去焦点handleClickOutside(event) {var isTargetOrChild = event.target.classNameif (isTargetOrChild !== '' &&isTargetOrChild !== 'el-icon-edit' &&isTargetOrChild !== 'el-input__inner') {this.rowIndex = -1this.columnIndex = -1this.iputIndex = -1 // 此处解决点击方框极近处}},/** --------------------------输入框相关事件-------------------------- */// 显示输入框inputShow(scope) {this.iputIndex = scope.row.indexthis.rowIndex = scope.row.indexthis.columnIndex = scope.column.index},// 输入框编辑名字inputEditName(row) {this.iputIndex = -1this.rowIndex = -1this.columnIndex = -1row.editLoading = truesetTimeout(function() {// 使用替换整个对象而不是修改其属性也是一个解决方案。这可以确保 Vue 检测到变化并更新视图/* const updatedRow = { ...row, editLoading: false }this.tableData.splice(this.tableData.indexOf(row), 1, updatedRow) */row.editLoading = falsethis.$set(this.tableData, row.index, row)// console.log('失去焦点', this.tableData)}.bind(this), 1000)},/** --------------------------选择框相关事件-------------------------- */// 失去焦点初始化selectBlur() {this.rowIndex = -1this.columnIndex = -1},// 选择框打开关闭下拉框事件selectVisibleChange(val) {if (!val) {this.selectBlur()}},// 对比选择框两个数组是否相等arraysEqual(arr1, arr2) {if (arr1.length !== arr2.length) return falsereturn arr1.every((value, index) => value === arr2[index])},// 选择框标签关闭事件selectTagClose(val, row) {const isEqual = this.arraysEqual(this.originalData, val)if (!isEqual) {row.province_name = val.map(id => {const option = this.optionsList.find(option => option.id === id)return option ? option.name : null // 如果找不到对应的id,则返回null})// 表格重新刷新this.$set(this.tableData, row.index, row)}},// 选择框当前选中值变化事件selectChange(val, row) {const isEqual = this.arraysEqual(this.originalData, val)if (!isEqual) {row.province_name = val.map(id => {const option = this.optionsList.find(option => option.id === id)return option ? option.name : null // 如果找不到对应的id,则返回null})// 表格重新刷新this.$set(this.tableData, row.index, row)}}}
}
</script>
<style lang="scss" scoped></style>

3.嵌入DatePicker日期选择器

在之前代码的基础上继续嵌入DatePicker日期选择器。效果如下:
在这里插入图片描述

因为日期选择器宽度不够的情况下显示的时间会被遮挡,如图所示
在这里插入图片描述
所以我们需要改变列宽,在data属性中添加一个宽度数据dateTimeWidth

data() {return {.../* --------------------------日期选择器相关属性-------------------------- */dateTimeWidth: 150}},

在表格点击单元格事件中修改列宽dateTimeWidth 和保存未修改的原始数据originalData

// 表格点击事件handleCellClick(row, column, cell, event) {this.rowIndex = row.indexthis.columnIndex = column.indexvar ifproperty = Object.prototype.hasOwnProperty.call(column, 'property')if (ifproperty) {const property = column.property...if (property === 'date') {this.dateTimeWidth = 200this.$nextTick(() => {this.$refs['dateTime' + row.id].focus()this.originalData = row.date// console.log('原始数据', this.originalData)})}}},

我们还需要用到DatePicker日期选择器的blur和change事件。
在这里插入图片描述
在DOM中根据 scope.row.index == iputIndex &&scope.column.index == columnIndex,当点击单元格的索引坐标和数据的索引坐标都一样的时候,显示对应的日期选择器。完整代码如下:

<template><div class="app-container" @click="handleClickOutside"><el-table :data="tableData" border style="width: 800px;" :row-class-name="tableRowIndex" :cell-class-name="tableCellIndex" @cell-click="handleCellClick"><el-table-column fixed prop="date" label="日期" :width="dateTimeWidth"><template slot-scope="scope"><el-date-pickerv-if="scope.row.index === rowIndex && scope.column.index === columnIndex":ref="'dateTime' + scope.row.id"v-model="scope.row.date"type="date"style="width: 100%"format="yyyy-MM-dd"value-format="timestamp"@blur="componentsBlur"@change="dateChange(scope.row)"/><span v-else style="cursor: pointer;">{{ scope.row.date | parseDate("{y}-{m}-{d}") }}</span></template></el-table-column><el-table-column prop="name" label="姓名" width="120"><template slot-scope="scope"><template v-if="scope.row.index == iputIndex && scope.column.index == columnIndex && scope.row.index == rowIndex"><el-input:ref="'sortNumRef' + scope.row.id"v-model="scope.row.name"size="small"autofocus="true"@blur="inputEditName(scope.row)"/></template><template v-if="scope.row.editLoading"><i class="el-icon-loading" /></template><template v-if="scope.row.index != iputIndex && !scope.row.editLoading"><span>{{ scope.row.name }}</span><el-button type="text" icon="el-icon-edit" style="margin-left: 10px" @click="inputShow(scope)" /></template></template></el-table-column><el-table-column prop="province" label="省份" width="200"><template slot-scope="scope"><el-selectv-if="rowIndex === scope.row.index && columnIndex === scope.column.index":ref="'sortNum' + scope.row.id"v-model="scope.row.province"style="width: 100%"size="small"filterablemultipleplaceholder="请选择"@blur="componentsBlur"@visible-change="selectVisibleChange"@remove-tag="selectTagClose(scope.row.province,scope.row)"@change="selectChange(scope.row.province,scope.row)"><el-option v-for="item in optionsList" :key="item.id" :label="item.name" :value="item.id" /></el-select><span v-else style="cursor: pointer;">{{ Array.isArray(scope.row.province_name)? scope.row.province_name.join(","): "" }}</span></template></el-table-column><el-table-column prop="city" label="市区" width="120" /><el-table-column prop="address" label="地址" width="300" /><el-table-column prop="zip" label="邮编" width="120" /><el-table-column fixed="right" label="操作" width="100"><template slot-scope="scope"><el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button><el-button type="text" size="small">编辑</el-button></template></el-table-column></el-table></div>
</template><script>
export default {name: 'Testdemo',filters: {parseDate(time, cFormat) {if (arguments.length === 0) {return null}const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'let dateif (typeof time === 'object') {date = time} else {if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {time = parseInt(time)}if ((typeof time === 'number') && (time.toString().length === 10)) {time = time * 1000}date = new Date(time)}const formatObj = {y: date.getFullYear(),m: date.getMonth() + 1,d: date.getDate(),h: date.getHours(),i: date.getMinutes(),s: date.getSeconds(),a: date.getDay()}const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {const value = formatObj[key]// Note: getDay() returns 0 on Sundayif (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }return value.toString().padStart(2, '0')})return time_str}},data() {return {tableData: [{ id: 1, date: 1462118400000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 1, address: '上海市普陀区金沙江路 1518 弄', zip: 200333 },{ id: 2, date: 1462291200000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 2, address: '上海市普陀区金沙江路 1517 弄', zip: 200333 },{ id: 3, date: 1462032000000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 3, address: '上海市普陀区金沙江路 1519 弄', zip: 200333 },{ id: 4, date: 1462204800000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 4, address: '上海市普陀区金沙江路 1516 弄', zip: 200333 }],// 原始数据,用来和修改的数据进行对比,有变化才能提交数据,否则不提交。originalData: null,// 表格行内编辑相关属性rowIndex: -1, // 行索引columnIndex: -1, // 列索引/* --------------------------输入框相关属性-------------------------- */iputIndex: -1, // 输入框索引/* --------------------------下拉框相关属性-------------------------- */optionsList: [{ id: 1, name: '上海' },{ id: 2, name: '重庆' },{ id: 3, name: '北京' }],/* --------------------------日期选择器相关属性-------------------------- */dateTimeWidth: 150}},// 监听属性computed: {},// 生命周期mounted() {},created() {},// 方法methods: {handleClick(row) {console.log(row)},/* --------------------------行内编辑相关基础方法-------------------------- */// 把每一行的索引加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格tableRowIndex({ row, rowIndex }) {// console.log(rowIndex)// 初始化行数据,将索引添加到行数据中row.index = rowIndex},// 把每一列的索引加到列数据中tableCellIndex({ column, columnIndex }) {// 初始化行数据,将索引添加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格column.index = columnIndex},// 表格点击事件handleCellClick(row, column, cell, event) {this.rowIndex = row.indexthis.columnIndex = column.indexvar ifproperty = Object.prototype.hasOwnProperty.call(column, 'property')if (ifproperty) {const property = column.propertyif (property === 'province') {this.$nextTick(() => {this.$refs['sortNum' + row.id].focus()this.originalData = Array.from(row.province)// console.log('原始数据', this.originalData)})}if (property === 'date') {this.dateTimeWidth = 200this.$nextTick(() => {this.$refs['dateTime' + row.id].focus()this.originalData = row.date// console.log('原始数据', this.originalData)})}}},// 监听鼠标点击表格外面区域的时候,行内编辑失去焦点handleClickOutside(event) {var isTargetOrChild = event.target.classNameif (isTargetOrChild !== '' &&isTargetOrChild !== 'el-icon-edit' &&isTargetOrChild !== 'el-input__inner') {this.rowIndex = -1this.columnIndex = -1this.iputIndex = -1 // 此处解决点击方框极近处}},// 组件失去焦点初始化componentsBlur() {this.rowIndex = -1this.columnIndex = -1},/** --------------------------输入框相关事件-------------------------- */// 显示输入框inputShow(scope) {this.iputIndex = scope.row.indexthis.rowIndex = scope.row.indexthis.columnIndex = scope.column.index},// 输入框编辑名字inputEditName(row) {this.iputIndex = -1this.rowIndex = -1this.columnIndex = -1row.editLoading = truesetTimeout(function() {// 使用替换整个对象而不是修改其属性也是一个解决方案。这可以确保 Vue 检测到变化并更新视图/* const updatedRow = { ...row, editLoading: false }this.tableData.splice(this.tableData.indexOf(row), 1, updatedRow) */row.editLoading = falsethis.$set(this.tableData, row.index, row)// console.log('失去焦点', this.tableData)}.bind(this), 1000)},/** --------------------------选择框相关事件-------------------------- */// 选择框打开关闭下拉框事件selectVisibleChange(val) {if (!val) {this.componentsBlur()}},// 对比选择框两个数组是否相等arraysEqual(arr1, arr2) {if (arr1.length !== arr2.length) return falsereturn arr1.every((value, index) => value === arr2[index])},// 选择框标签关闭事件selectTagClose(val, row) {const isEqual = this.arraysEqual(this.originalData, val)if (!isEqual) {row.province_name = val.map(id => {const option = this.optionsList.find(option => option.id === id)return option ? option.name : null // 如果找不到对应的id,则返回null})// 表格重新刷新this.$set(this.tableData, row.index, row)}},// 选择框当前选中值变化事件selectChange(val, row) {const isEqual = this.arraysEqual(this.originalData, val)if (!isEqual) {row.province_name = val.map(id => {const option = this.optionsList.find(option => option.id === id)return option ? option.name : null // 如果找不到对应的id,则返回null})// 表格重新刷新this.$set(this.tableData, row.index, row)}},/** --------------------------时间选择器相关事件-------------------------- */// 计划结束时间发生变化dateChange(row) {this.dateTimeWidth = 150if (row.date !== this.originalData) {// 表格重新刷新this.$set(this.tableData, row.index, row)} else {this.componentsBlur()this.$message.error('时间不可清空')}}}
}
</script>
<style lang="scss" scoped></style>

3.1遇到问题

1.表格的数据日期格式是时间戳格式,需要将时间戳转化为常见‘年-月-日’格式

这个问题可以用vue的过滤器filters来解决,定义一个时间戳格式化过滤器

4.嵌入表单弹出框组件

继续在之前的代码上嵌入表单弹出框组件,我们首先需要对表格调整下数据,新增一列‘处理状态status’数据。效果如图:
在这里插入图片描述
同时,需要在data属性中,添加表单弹窗组件的属性,状态数据列表statusList、状态颜色数据statusColor、表单数据form和表单验证规则数据formRules

data() {return {tableData: [{ id: 1, date: 1462118400000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 1, address: '上海市普陀区金沙江路 1518 弄', zip: 200333 },{ id: 2, date: 1462291200000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 2, address: '上海市普陀区金沙江路 1517 弄', zip: 200333 },{ id: 3, date: 1462032000000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 3, address: '上海市普陀区金沙江路 1519 弄', zip: 200333 },{ id: 4, date: 1462204800000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 4, address: '上海市普陀区金沙江路 1516 弄', zip: 200333 }],.../* --------------------------表单弹出框相关属性-------------------------- */statusList: [{ id: 1, name: '新增加' },{ id: 2, name: '处理中' },{ id: 3, name: '已完成' },{ id: 4, name: '延期办理' },{ id: 5, name: '已取消' }],statusColor: ['#52c41a', '#2f54eb', '#b8bac1', '#fa541c', '#b8bac1'],form: {status: null, // 状态handler: null, // 处理人comment: null // 备注内容},formRules: {handler: [{ required: true, message: '请选择处理人', trigger: 'blur' }]}}},

我们要用到Popover弹出框的show和hide事件。
在这里插入图片描述
Form 表单组件方面我们需要对其绑定表单数据form、表单验证数据formRules。完整代码如下:

<template><div class="app-container" @click="handleClickOutside"><el-table :data="tableData" border style="width: 800px;" :row-class-name="tableRowIndex" :cell-class-name="tableCellIndex" @cell-click="handleCellClick"><el-table-column fixed prop="date" label="日期" :width="dateTimeWidth"><template slot-scope="scope"><el-date-pickerv-if="scope.row.index === rowIndex && scope.column.index === columnIndex":ref="'dateTime' + scope.row.id"v-model="scope.row.date"type="date"style="width: 100%"format="yyyy-MM-dd"value-format="timestamp"@blur="componentsBlur"@change="dateChange(scope.row)"/><span v-else style="cursor: pointer;">{{ scope.row.date | parseDate("{y}-{m}-{d}") }}</span></template></el-table-column><el-table-column prop="name" label="姓名" width="120"><template slot-scope="scope"><template v-if="scope.row.index == iputIndex && scope.column.index == columnIndex && scope.row.index == rowIndex"><el-input:ref="'sortNumRef' + scope.row.id"v-model="scope.row.name"size="small"autofocus="true"@blur="inputEditName(scope.row)"/></template><template v-if="scope.row.editLoading"><i class="el-icon-loading" /></template><template v-if="scope.row.index != iputIndex && !scope.row.editLoading"><span>{{ scope.row.name }}</span><el-button type="text" icon="el-icon-edit" style="margin-left: 10px" @click="inputShow(scope)" /></template></template></el-table-column><el-table-column prop="province" label="省份" width="200"><template slot-scope="scope"><el-selectv-if="rowIndex === scope.row.index && columnIndex === scope.column.index":ref="'sortNum' + scope.row.id"v-model="scope.row.province"style="width: 100%"size="small"filterablemultipleplaceholder="请选择"@blur="componentsBlur"@visible-change="selectVisibleChange"@remove-tag="selectTagClose(scope.row.province,scope.row)"@change="selectChange(scope.row.province,scope.row)"><el-option v-for="item in optionsList" :key="item.id" :label="item.name" :value="item.id" /></el-select><span v-else style="cursor: pointer;">{{ Array.isArray(scope.row.province_name)? scope.row.province_name.join(","): "" }}</span></template></el-table-column><el-table-column prop="status" label="处理状态" align="center" width="110"><template slot-scope="{ row, $index }"><el-popover:ref="'Popover' + row.id"width="700"trigger="click"@show="showPopover(row)"@hide="hidePopover"><el-row style="padding: 20px"><el-col :span="6"><el-radio-group :ref="'PopoverRadio' + row.id" v-model="form.status" size="small"><el-radiov-for="(item, index) in statusList":key="index"style="margin-bottom: 20px":label="item.id">{{ item.name }}</el-radio></el-radio-group></el-col><el-col :span="18" style="border-left: 1px solid #eee; padding-left: 20px"><el-form :ref="'formData' + row.id" label-width="80px" :model="form" :rules="formRules"><el-form-item label="处理人" prop="handler"><el-input v-model="form.handler" placeholder="请输入姓名" /></el-form-item><el-form-item label="评论" prop="comment"><el-input v-model="form.comment" type="textarea" /></el-form-item><el-form-item><el-button type="primary" @click="handleSubmit(row, $index)">提交</el-button><el-button @click="handleCancel(row, $index)">取消</el-button></el-form-item></el-form></el-col></el-row><el-buttonslot="reference"roundsize="mini":style="'color:' + statusColor[row.status - 1] + ';font-weight:bold;'">{{ statusList[row.status - 1] ? statusList[row.status - 1].name : "" }}</el-button></el-popover></template></el-table-column><el-table-column prop="city" label="市区" width="120" /><el-table-column prop="address" label="地址" width="300" /><el-table-column prop="zip" label="邮编" width="120" /><el-table-column fixed="right" label="操作" width="100"><template slot-scope="scope"><el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button><el-button type="text" size="small">编辑</el-button></template></el-table-column></el-table></div>
</template><script>
export default {name: 'Testdemo',filters: {parseDate(time, cFormat) {if (arguments.length === 0) {return null}const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'let dateif (typeof time === 'object') {date = time} else {if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {time = parseInt(time)}if ((typeof time === 'number') && (time.toString().length === 10)) {time = time * 1000}date = new Date(time)}const formatObj = {y: date.getFullYear(),m: date.getMonth() + 1,d: date.getDate(),h: date.getHours(),i: date.getMinutes(),s: date.getSeconds(),a: date.getDay()}const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {const value = formatObj[key]// Note: getDay() returns 0 on Sundayif (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }return value.toString().padStart(2, '0')})return time_str}},data() {return {tableData: [{ id: 1, date: 1462118400000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 1, address: '上海市普陀区金沙江路 1518 弄', zip: 200333 },{ id: 2, date: 1462291200000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 2, address: '上海市普陀区金沙江路 1517 弄', zip: 200333 },{ id: 3, date: 1462032000000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 3, address: '上海市普陀区金沙江路 1519 弄', zip: 200333 },{ id: 4, date: 1462204800000, name: '王小虎', province: [1], province_name: ['上海'], city: '普陀区', status: 4, address: '上海市普陀区金沙江路 1516 弄', zip: 200333 }],// 原始数据,用来和修改的数据进行对比,有变化才能提交数据,否则不提交。originalData: null,// 表格行内编辑相关属性rowIndex: -1, // 行索引columnIndex: -1, // 列索引/* --------------------------输入框相关属性-------------------------- */iputIndex: -1, // 输入框索引/* --------------------------下拉框相关属性-------------------------- */optionsList: [{ id: 1, name: '上海' },{ id: 2, name: '重庆' },{ id: 3, name: '北京' }],/* --------------------------日期选择器相关属性-------------------------- */dateTimeWidth: 150,/* --------------------------表单弹出框相关属性-------------------------- */statusList: [{ id: 1, name: '新增加' },{ id: 2, name: '处理中' },{ id: 3, name: '已完成' },{ id: 4, name: '延期办理' },{ id: 5, name: '已取消' }],statusColor: ['#52c41a', '#2f54eb', '#b8bac1', '#fa541c', '#b8bac1'],form: {status: null, // 状态handler: null, // 处理人comment: null // 备注内容},formRules: {handler: [{ required: true, message: '请选择处理人', trigger: 'blur' }]}}},// 监听属性computed: {},// 生命周期mounted() {},created() {},// 方法methods: {handleClick(row) {console.log(row)},/* --------------------------行内编辑相关基础方法-------------------------- */// 把每一行的索引加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格tableRowIndex({ row, rowIndex }) {// console.log(rowIndex)// 初始化行数据,将索引添加到行数据中row.index = rowIndex},// 把每一列的索引加到列数据中tableCellIndex({ column, columnIndex }) {// 初始化行数据,将索引添加到行数据中,以便以后明确点击事件是哪一行哪一列的单元格column.index = columnIndex},// 表格点击事件handleCellClick(row, column, cell, event) {this.rowIndex = row.indexthis.columnIndex = column.indexvar ifproperty = Object.prototype.hasOwnProperty.call(column, 'property')if (ifproperty) {const property = column.propertyif (property === 'province') {this.$nextTick(() => {this.$refs['sortNum' + row.id].focus()this.originalData = Array.from(row.province)// console.log('原始数据', this.originalData)})}if (property === 'date') {this.dateTimeWidth = 200this.$nextTick(() => {this.$refs['dateTime' + row.id].focus()this.originalData = row.date// console.log('原始数据', this.originalData)})}}},// 监听鼠标点击表格外面区域的时候,行内编辑失去焦点handleClickOutside(event) {var isTargetOrChild = event.target.classNameif (isTargetOrChild !== '' &&isTargetOrChild !== 'el-icon-edit' &&isTargetOrChild !== 'el-input__inner') {this.rowIndex = -1this.columnIndex = -1this.iputIndex = -1 // 此处解决点击方框极近处}},// 组件失去焦点初始化componentsBlur() {this.rowIndex = -1this.columnIndex = -1},/** --------------------------输入框相关事件-------------------------- */// 显示输入框inputShow(scope) {this.iputIndex = scope.row.indexthis.rowIndex = scope.row.indexthis.columnIndex = scope.column.index},// 输入框编辑名字inputEditName(row) {this.iputIndex = -1this.rowIndex = -1this.columnIndex = -1row.editLoading = truesetTimeout(function() {// 使用替换整个对象而不是修改其属性也是一个解决方案。这可以确保 Vue 检测到变化并更新视图/* const updatedRow = { ...row, editLoading: false }this.tableData.splice(this.tableData.indexOf(row), 1, updatedRow) */row.editLoading = falsethis.$set(this.tableData, row.index, row)// console.log('失去焦点', this.tableData)}.bind(this), 1000)},/** --------------------------选择框相关事件-------------------------- */// 选择框打开关闭下拉框事件selectVisibleChange(val) {if (!val) {this.componentsBlur()}},// 对比选择框两个数组是否相等arraysEqual(arr1, arr2) {if (arr1.length !== arr2.length) return falsereturn arr1.every((value, index) => value === arr2[index])},// 选择框标签关闭事件selectTagClose(val, row) {const isEqual = this.arraysEqual(this.originalData, val)if (!isEqual) {row.province_name = val.map(id => {const option = this.optionsList.find(option => option.id === id)return option ? option.name : null // 如果找不到对应的id,则返回null})// 表格重新刷新this.$set(this.tableData, row.index, row)}},// 选择框当前选中值变化事件selectChange(val, row) {const isEqual = this.arraysEqual(this.originalData, val)if (!isEqual) {row.province_name = val.map(id => {const option = this.optionsList.find(option => option.id === id)return option ? option.name : null // 如果找不到对应的id,则返回null})// 表格重新刷新this.$set(this.tableData, row.index, row)}},/** --------------------------时间选择器相关事件-------------------------- */// 计划结束时间发生变化dateChange(row) {this.dateTimeWidth = 150if (row.date !== this.originalData) {// 表格重新刷新this.$set(this.tableData, row.index, row)} else {this.componentsBlur()this.$message.error('时间不可清空')}},/** --------------------------表单弹出框相关事件-------------------------- */// 初始化弹层窗showPopover(row) {this.form.status = row.status // 状态this.form.originalData = row.status},// 隐藏状态弹层窗hidePopover() {this.form = {status: null, // 状态handler: null, // 处理人comment: null // 备注内容}},// 提交操作handleSubmit(row) {var ref = 'formData' + row.idthis.$refs[ref].validate((valid) => {if (valid) {if (this.form.status !== this.originalData) {// 发起后端请求row.status = this.form.statusthis.$set(this.tableData, row.index, row) // 表格重新刷新this.resetForm(row, row.index) // 重置表单} else {this.resetForm(row, row.index)}// console.log('提交操作', this.form)}})},// 重置表单resetForm(row, $index) {var ref = 'formData' + row.idthis.$refs[ref].resetFields()this.$refs[ref].clearValidate()this.form = {status: null, // 状态handler: null, // 处理人comment: null // 备注内容}document.body.click()},// 取消操作handleCancel(row) {this.resetForm(row, row.index)// console.log('取消操作', this.form)this.$message({message: '取消操作',type: 'warning'})}}
}
</script>
<style lang="scss" scoped></style>

4.1遇到问题

1.手动激活模式下的弹窗显示和关闭的问题

如果需要使用手动模式的弹出框,则不能使用v-model属性,主要原因是,因为表格渲染出多个v-model绑定同一个值的弹出框,所以如果绑定同一个v-model值的话,当v-model为true时,则会同时显示多个弹出框;
在这里插入图片描述

在这里插入图片描述

第二如果绑定v-model值的话,则无法使用doShow方法,虽然能输出的DOW对象里面包含doShow方法,但是调用的时候却是undefined。

在这里插入图片描述

去掉v-model绑定值,则正常显示弹出框。然后通过doClose方法来关闭。手动模式最大的缺点是很难做到点击表格外部来关闭弹出窗,只能将doClose方法绑定到’取消’按钮和重置表单方法上。因此我们使用的click激活模式的弹窗。

在这里插入图片描述

2.表单的验证功能显示不正常

主要原因是form表单组件的ref属性值都是一样的,点击提交之后,因为有多个ref所以验证出现问题。解决办法就是将ref属性绑定动态值

在这里插入图片描述


三、总结

这次行内编辑,让我学习到很多有用的知识,同时我这边在form弹出窗组件中发现一个关于单选的警告信息,通过网上资料找到是因为aria-hidden属性值为true导致的,一直没想到解决办法,如有知道的大神可告知下解决方法。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/78735.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c#OdbcDataReader的数据读取

先有如下c#示例代码&#xff1a; string strconnect "DSNcustom;UIDsa;PWD123456;" OdbcConnection odbc new OdbcConnection(strconnect); odbc.Open(); if (odbc.State ! System.Data.ConnectionState.Open) { return; } string strSql "select ID from my…

【HTML5】老式放映机原理-实现图片无缝滚动

老式放映机原理-实现图片无缝滚动 实现思路&#xff1a; 页面设计部分——先将视口div设置为相对定位&#xff0c;再视口div里面嵌套一个类似“胶卷”的div,把该div设置为绝对定位&#xff0c;此时“胶卷"会挂靠在视口上面&#xff0c;再将“胶卷”的left属性设置为负值…

LeetCode 1781. 所有子字符串美丽值之和 题解

示例 输入&#xff1a;s "aabcb" 输出&#xff1a;5 解释&#xff1a;美丽值不为零的字符串包括 ["aab","aabc","aabcb","abcb","bcb"] &#xff0c;每一个字符串的美丽值都为 1这题光用文字解说还是无法达到讲…

2025ACTF Web部分题解

文章目录 ACTF uploadnot so web 1not so web 2 ACTF upload 前面登录随便输入可以进入文件上传页面, 随便上传一张图片, 发现路由存在file_path参数, 尝试路径穿越读取文件 发现可以成功读取 读取源码 /upload?file_path../app.pyimport uuid import os import hashlib im…

双目标清单——AI与思维模型【96】

一、定义 双目标清单思维模型是一种将决策或任务分解为两个主要目标&#xff0c;并分别列出相关要素和行动步骤的思维方式。这两个目标通常具有相互关联又有所侧重的特点&#xff0c;通过明确并列出与每个目标相关的具体事项&#xff0c;有助于更清晰地分析问题、制定计划和分…

深度学习系统学习系列【6】之深度学习技巧

文章目录 数据集准备数据集扩展数据预处理1. 0均值&#xff08;Zero Centralization&#xff09;代码实现 2. 归一化&#xff08;Normalization&#xff09;代码实现 3. 主成分分析&#xff08;Principal Component Analysis, PCA&#xff09;实现步骤代码实现 4. 白化&#xf…

rfsoc petalinux适配调试记录

1。安装虚拟机 2.设置共享文件夹 https://xinzhi.wenda.so.com/a/1668239544201149先设置文件夹路径 vmware 12 下安装 ubuntu 16.04 后&#xff0c;按往常的惯例安装 vmware-tools&#xff0c;安装时提示建议使用 open-vm-tools&#xff0c;于是放弃 vmware-tools 的安装&am…

# YOLOv1:开启实时目标检测的新时代

YOLOv1&#xff1a;开启实时目标检测的新时代 在计算机视觉领域&#xff0c;目标检测一直是研究的热点和难点问题。它不仅需要准确地识别出图像中的物体&#xff0c;还需要确定这些物体的位置。YOLO&#xff08;You Only Look Once&#xff09;系列算法以其高效的实时目标检测…

uni-app vue3 实现72小时倒计时功能

功能介绍 &#xff0c;数组项有一个下单时间 &#xff0c;比如今天下单在72小时内可以继续支付&#xff0c;超过则默认取消订单 页面按钮处 加上倒计时 <!-- 倒计时 --> <text v-if"item.timeLeft > 0">{{ formatTime(item.remaining) }}</text&g…

一周学会Pandas2 Python数据处理与分析-Pandas2数据类型转换操作

锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili Pandas 提供了灵活的方法来处理数据类型转换&#xff0c;以下是常见操作及代码示例&#xff1a; 1. 查看数据类型 …

LLM损失函数面试会问到的

介绍一下KL散度 KL&#xff08;Kullback-Leibler散度衡量了两个概率分布之间的差异。其公式为&#xff1a; D K L ( P / / Q ) − ∑ x ∈ X P ( x ) log ⁡ 1 P ( x ) ∑ x ∈ X P ( x ) log ⁡ 1 Q ( x ) D_{KL}(P//Q)-\sum_{x\in X}P(x)\log\frac{1}{P(x)}\sum_{x\in X}…

基于CBOW模型的词向量训练实战:从原理到PyTorch实现

基于CBOW模型的词向量训练实战&#xff1a;从原理到PyTorch实现 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;词向量是将单词映射为计算机可处理的数值向量的重要方式。通过词向量&#xff0c;单词之间的语义关系能够以数学形式表达&#xff0c;为后续的文本分…

Linux——进程终止/等待/替换

前言 本章主要对进程终止&#xff0c;进程等待&#xff0c;进程替换的详细认识&#xff0c;根据实验去理解其中的原理&#xff0c;干货满满&#xff01; 1.进程终止 概念&#xff1a;进程终止就是释放进程申请的内核数据结构和对应的代码和数据 进程退出的三种状态 代码运行…

iOS开发架构——MVC、MVP和MVVM对比

文章目录 前言MVC&#xff08;Model - View - Controller&#xff09;MVP&#xff08;Model - View - Presenter&#xff09;MVVM&#xff08;Model - View - ViewModel&#xff09; 前言 在 iOS 开发中&#xff0c;MVC、MVVM、和 MVP 是常见的三种架构模式&#xff0c;它们主…

0506--01-DA

36. 单选题 在娱乐方式多元化的今天&#xff0c;“ ”是不少人&#xff08;特别是中青年群体&#xff09;对待戏曲的态度。这里面固然存在 的偏见、难以静下心来欣赏戏曲之美等因素&#xff0c;却也有另一个无法回避的原因&#xff1a;一些戏曲虽然与观众…

关于Java多态简单讲解

面向对象程序设计有三大特征&#xff0c;分别是封装&#xff0c;继承和多态。 这三大特性相辅相成&#xff0c;可以使程序员更容易用编程语言描述现实对象。 其中多态 多态是方法的多态&#xff0c;是通过子类通过对父类的重写&#xff0c;实现不同子类对同一方法有不同的实现…

【Trea】Trea国际版|海外版下载

Trea目前有两个版本&#xff0c;海外版和国内版。‌ Trae 版本差异 ‌大模型选择‌&#xff1a; ‌国内版‌&#xff1a;提供了字节自己的Doubao-1.5-pro以及DeepSeek的V3版本和R1版本。海外版&#xff1a;提供了ChartGPT以及Claude-3.5-Sonnet和3.7-Sonnt. ‌功能和界面‌&a…

Missashe考研日记-day33

Missashe考研日记-day33 1 专业课408 学习时间&#xff1a;2h30min学习内容&#xff1a; 今天开始学习OS最后一章I/O管理的内容&#xff0c;听了第一小节的内容&#xff0c;然后把课后习题也做了。知识点回顾&#xff1a; 1.I/O设备分类&#xff1a;按信息交换单位、按设备传…

链表的面试题3找出中间节点

来来来&#xff0c;接着继续我们的第三道题 。 解法 暴力求解 快慢指针 https://leetcode.cn/problems/middle-of-the-linked-list/submissions/ 这道题的话&#xff0c;思路是非常明确的&#xff0c;就是让你找出我们这个所谓的中间节点并且输出。 那这道题我们就需要注意…

linux磁盘介绍与LVM管理

一、磁盘基本概述 GPT是全局唯一标识分区表的缩写,是全局唯一标示磁盘分区表格式。而MBR则是另一种磁盘分区形式,它是主引导记录的缩写。相比之下,MBR比GPT出现得要更早一些。 MBR 与 GPT MBR 支持的磁盘最大容量为 2 TB,GPT 最大支持的磁盘容量为 18 EB,当前数据盘支持…