运用到实际项目可能有帮助的点:
el-table嵌套input的实际使用
多选和单选的答案排版显示切换
v-model改变了但页面没渲染的解决方式
封装组件的思想
前几天做了一个表单组件 分享一下感受(vue2)
先上图
点击新增或者编辑会进入表单组件并且触发组件内的init方法,编辑会带该题的id,新建则是空。(父组件代码就不摆上来了)
子组件代码
<template>
<transition name="el-zoom-in-center">
<div class="JNPF-preview-main">
<div class="JNPF-common-page-header">
<el-page-header @back="goBack" :content="!dataForm.id ? '新建' : '编辑'" />
<div class="options">
<el-button type="primary" @click="dataFormSubmit()" :loading="btnLoading">确 定</el-button>
<el-button @click="goBack">取 消</el-button>
</div>
</div>
<div :style="{ margin: '0 auto', width: '100%' }">
<el-row :gutter="15" class=" main">
<el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right"
:rules="rules">
<el-col :span="24">
<el-form-item label="分类" prop="Category">
<el-select v-model='dataForm.Category' placeholder='请选择' clearable required
:style='{ "width": "100%" }'>
<el-option v-for="(item, index) in CategoryOptions" :key="index" :label="item.fullName"
:value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="题型" prop="QuestionType">
<el-radio-group v-model='dataForm.QuestionType' @change="(e) => QuestionTypeIs(e)" required>
<el-radio v-for="(item, index) in QuestionTypeOptions" :key="index" :label="item.id">{{
item.fullName }} </el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="题干" prop="QuestionStem">
<el-input v-model='dataForm.QuestionStem' placeholder='请输入' clearable required
:style='{ "width": "100%" }'>
</el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label-width="0">
<div class="JNPF-common-title">
<h2>选项内容</h2>
</div>
<el-table :data="dataForm.Options" size='mini'>
<el-table-column type="index" width="50" label="序号" align="center" />
<el-table-column prop="Options" label="选项内容">
<template slot="header">
<span class="required-sign">*</span>选项内容
</template>
<template slot-scope="scope">
<el-input v-model="dataForm.Options[scope.$index]" :style='{ "width": "100%" }'
placeholder='请输入' clearable required>
</el-input>
</template>
</el-table-column>
<el-table-column label="操作" width="50">
<template slot-scope="scope">
<el-button size="mini" type="text" class="JNPF-table-delBtn"
@click="handleDelEmaQuestionOptionEntityList(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="table-actions" @click="addHandleEmaQuestionOptionEntityList()">
<el-button type="text" icon="el-icon-plus">新增</el-button>
</div>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="答案" prop="Answer" v-if="QuestionType == 1">
<el-select v-model='dataForm.Answer' placeholder='请选择' clearable required
:style='{ "width": "100%" }'>
<el-option v-for="(item, index) in dataForm.Options" :key="index" :label="index + 1"
:value="index + 1"></el-option>
</el-select>
</el-form-item>
<el-form-item label="答案" prop="Answer" v-if="QuestionType == 2">
<el-select v-model="dataForm.Answer" placeholder="请选择" :style='{ "width": "100%" }'
clearable required multiple>
<el-option v-for="(item, index) in dataForm.Options" :key="index" :label="index + 1"
:value="index + 1">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="分值" prop="Point">
<el-input-number v-model='dataForm.Point' placeholder='数字文本' required :step='1'
controls-position='right' :max='100' :min='1'>
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="是否有效" prop="F_EnabledMark">
<el-switch v-model='dataForm.F_EnabledMark' :active-value='1' :inactive-value='0'>
</el-switch>
</el-form-item>
</el-col>
<el-col :span="24" v-if='false'>
<el-form-item label="创建用户" prop="F_CreatorUserId">
<jnpf-open-data v-model='dataForm.F_CreatorUserId' readonly type='currUser'>
</jnpf-open-data>
</el-form-item>
</el-col>
<el-col :span="24" v-if='false'>
<el-form-item label="创建时间" prop="F_CreatorTime">
<jnpf-open-data v-model='dataForm.F_CreatorTime' readonly type='currTime'>
</jnpf-open-data>
</el-form-item>
</el-col>
<el-col :span="24" v-if='false'>
<el-form-item label="修改用户" prop="F_LastModifyUserId">
<el-input v-model='dataForm.F_LastModifyUserId' placeholder='系统自动生成' readonly>
</el-input>
</el-form-item>
</el-col>
<el-col :span="24" v-if='false'>
<el-form-item label="修改时间" prop="F_LastModifyTime">
<el-input :value='dataForm.f_LastModifyTime | toDate' placeholder='系统自动生成' readonly />
</el-form-item>
</el-col>
</el-form>
</el-row>
</div>
</div>
</transition>
</template>
<script>
import request from '@/utils/request'
import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
export default {
components: {},
props: [],
data() {
return {
btnLoading: false,
loading: false,
visible: false,
dataForm: {
id: '',
Category: '',
QuestionType: "1",
QuestionStem: '',
Answer: [],
Point: 5,
F_EnabledMark: 0,
F_CreatorUserId: '',
F_CreatorTime: '',
F_LastModifyUserId: '',
F_LastModifyTime: '',
},
QuestionType: 1,
rules: {
Category: [
{
required: true,
message: '请输入分类',
trigger: 'change'
},
],
QuestionType: [
{
required: true,
message: '请输入题型',
trigger: 'change'
},
],
QuestionStem: [
{
required: true,
message: '请输入题干',
trigger: 'blur'
},
],
Answer: [
{
required: true,
message: '请输入答案',
trigger: 'change'
},
],
Point: [
{
required: true,
message: '请输入分值',
trigger: [
"blur",
"change"
]
},
],
},
CategoryOptions: [],
}
},
computed: {},
watch: {},
created() {
this.getcategoryOptions();
},
mounted() {
},
computed: {
},
watch: {
},
methods: {
// 非空校验
emaQuestionOptionExist() {
let isOk = true;
for (let i = 0; i < this.dataForm.Options.length; i++) {
const e = this.dataForm.Options[i];
if (!e) {
this.$message({
message: '选项内容不能为空',
type: 'error',
duration: 1000
});
isOk = false
break
}
if (this.QuestionType == 2) {
if (this.dataForm.Answer.length == 1) {
this.$message({
message: '多选题答案应为两个及以上',
type: 'error',
duration: 1000
});
isOk = false
break
}
}
}
return isOk;
},
// 获取试题分类数据(消防安全等等..)
getcategoryOptions() {
getDictionaryDataSelector('397272689904988741').then(res => {
this.CategoryOptions = res.data.list
});
},
// 关闭
goBack() {
this.$emit('refresh')
},
// 点开
init(id) {
this.dataForm.id = id || '';
this.visible = true;
this.$nextTick(() => {
this.$refs['elForm'].resetFields();
this.dataForm.Options = [];
// 编辑操作
if (this.dataForm.id) {
request({
url: `api/visualdev/OnlineDev/380291022044793029/${this.dataForm.id}`,
method: 'get'
}).then(res => {
this.dataForm = res.data.data
this.dataForm.id = id || '';
this.dataForm.Answer = JSON.parse(this.dataForm.Answer);
this.QuestionType = this.dataForm.QuestionType || 1
})
// 新建操作
}else{
this.QuestionType = 1
}
});
this.$store.commit('generator/UPDATE_RELATION_DATA', {})
},
// 多选单选切换
QuestionTypeIs(e) {
this.QuestionType = e
if (e == 1) this.dataForm.Answer = ''
if (e == 2) this.dataForm.Answer = []
},
// 提交确定
dataFormSubmit() {
this.$refs['elForm'].validate((valid) => {
if (valid) {
if (!this.emaQuestionOptionExist()) return;
this.btnLoading = true;
this.dataForm.F_EnabledMark = parseInt(this.dataForm.F_EnabledMark)
this.dataForm.flowId = ''
// 新建提交确定
if (!this.dataForm.id) {
request({
url: `/api/visualdev/OnlineDev/380291022044793029/`,
method: 'post',
data: {
id: this.dataForm.id,
data: this.dataForm
}
}).then((res) => {
this.$message({
message: res.msg,
type: 'success',
duration: 1000,
onClose: () => {
this.btnLoading = false;
this.visible = false,
this.$emit('refresh', true)
}
})
}).catch(() => {
this.btnLoading = false;
})
} else {
// 编辑提交确定
request({
url: `/api/visualdev/OnlineDev/380291022044793029/${this.dataForm.id}`,
method: 'PUT',
data: {
id: this.dataForm.id,
data: this.dataForm
}
}).then((res) => {
this.$message({
message: res.msg,
type: 'success',
duration: 1000,
onClose: () => {
this.btnLoading = false;
this.visible = false
this.$emit('refresh', true)
}
})
}).catch(() => {
this.btnLoading = false;
})
}
}
})
},
// 选项新增
addHandleEmaQuestionOptionEntityList() {
let item = ''
this.dataForm.Options.push(item)
if (!this.dataForm.id) this.$forceUpdate()
},
// 选项删除
handleDelEmaQuestionOptionEntityList(index) {
this.dataForm.Options.splice(index, 1);
if (!this.dataForm.id) this.$forceUpdate()
},
}
}
</script>
编辑实际图
新增实际图
代码不复杂 且都做了注释
主要是分享下el-table嵌套input项目中的实际运用(插槽的使用),还有怎么实现一个简洁可编辑响应式表单(新增 编辑 删除)的业务需求
其中需要注意的目前回忆起来有几点:
el-select多选框的multiple属性(可多选)需要是一个数组,所以每次都需要切换
如果反复切换,数组和字符串的方法转化会多很多不要的标点符号,所以每次切换得清空值
scope里的$index可以拿到循环里的下标
新建的时候选项的值更新了 但是没有进到dataForm.Options里面去 所以我用了this.$forceUpdate()。
第四点奇怪的是编辑时候是正常的 能同步到select去,但是新建就不行得用强制刷新,这个问题我还在疑惑,希望有大佬解惑。