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 協議》,轉載必須註明作者和本文連結