数据变动与渲染问题
1.需求
- 实现一个动态表单,要求传入一个数组,自动生成表单内容
- 为了简单,用多组按钮来演示
- 一个按钮一个数据单元,包括按钮名称,按钮值,和按钮样式
2.实现效果
实现代码
son.vue 文件
<template>
<view>
<block v-for="(v,i) in selects" :key="i">
<view class="cu-form-group flex-left">
<view class="title">{{v.label}}</view>
<view class="grid col-3 padding-sm">
<button v-for="(radio,i2) in v.options" :key="i2" class="cu-btn margin-right orange block" @click="onRadioChange" :class="radio.value == propMap[v.name].selected?'bg-orange':'line-orange'" :data-name="v.name" :data-value="radio.value">
{{radio.label}}
</button>
</view>
</view>
</block>
</view>
</template>
<script lang="ts" src="./son.ts"></script>
son.ts文件
import Vue from 'vue';
import { Component } from 'vue-property-decorator';
@Component({
props: ['selects']
})
export default class SonComponent extends Vue {
//如果没有这个map而是直接修改props的值,即使后续数据变动,页面将不会渲染。
propMap: any = {}
//要在挂载前将map的设置出来,如果页面拿到的某个值是undefined,即使后续数据变动,页面也不会渲染
created() {
//先将父组件传入的数组变成属性
this.$props.selects.forEach((v: any) => {
this.$set(this.propMap, v.name, v)
})
}
//当radio值改变的时候触发
onRadioChange(e: any) {
//获取当前点击的值
let value = e.currentTarget.dataset.value
//获取当前点击的名称
let name = e.currentTarget.dataset.name
console.log("当前点击的", name, value)
this.$props.selects.forEach((v: any, k: any) => {
if (v.name == name) {
v.selected = value
//提交给vue,让他去渲染
this.$set(this.propMap, v.name, v)
return
}
})
}
}
如代码中所示
- 如果改变父组件传入的props对象的值是不会体现到页面上的
- 要页面能监听到数据的变动,要给组件设置新的变量,并且这个变量在组件渲染前已经生成,绝对不能是undefined
- 改变数据的时候要用this.$set,而不是直接修改数据对象本身,否则页面不会重新渲染
文档指出,由于 JavaScript 的限制,Vue 不能检测以下数组的变动:
- 当你利用索引直接设置一个数组项时,例如:
vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:
vm.items.length = newLength
- Vue 不能检测对象属性的添加或删除:
这个时候需要
Vue.set(vm.items, indexOfItem, newValue) //现在是响应式的
//如果userProfile上没有age字段
vm.userProfile.age = 27 //不响应
Vue.set(vm.userProfile, 'age', 27) //现在是响应式的
4.父组件代码
example.vue文件
<template>
<view>
<view class="cu-modal bottom-modal show">
<view class="cu-dialog">
<view class="my-search-button-group text-size-main cu-bar bg-white">
<view class="action text-blue">取消</view>
<view class="action text-green">确定</view>
</view>
<!-- 筛选条件 s-->
<son-component :selects="selects"></son-component>
<!-- 筛选条件 e -->
<view class="bg-white" style="height:30px;"></view>
</view>
</view>
</view>
</template>
<script lang="ts" src="./example.ts"></script>
example.ts文件
import Vue from 'vue';
import { Component } from 'vue-property-decorator';
import SonComponent from '../components/son';
@Component({
components: {
SonComponent
},
data() {
let selects = [
{
label: "订单状态1",
name: "status",
selected: "",
options: [
{
label: "全部",
value: ""
},
{
label: "已到账",
value: "account"
},
{
label: "冻结中",
value: "freeze"
}
]
},
{
label: "订单状态2",
name: "status2",
selected: "",
options: [
{
label: "全部",
value: ""
},
{
label: "已到账",
value: "account"
},
{
label: "冻结中",
value: "freeze"
}
]
}
]
return { selects }
}
})
export default class Example extends Vue {
}
本作品采用《CC 协议》,转载必须注明作者和本文链接