Vue.js 对 TypeScript 的反应性和 Object.defineProperty
Vue.js reactivity and Object.defineProperty with TypeScript
我正在 TypeScript 中创建一个 class 来处理我的表单提交和服务器错误:
export default class Form<Model> {
private readonly original: Model
private changes: Partial<Model>
constructor(data: Model) {
this.original = data
Object.keys(this.original).forEach(key => this.initialiseData(key))
}
private initialiseData(key) {
Object.defineProperty(this, key, {
get: () => this.data[key],
set: (value) => this.changes[key] = value
}
}
get data(): Model {
return Object.assign({}, this.original, this.changes)
}
post(url: string) {
// post logic
}
}
这将在我的 Vue 组件中使用,如下所示:
import { Component, Vue } from 'vue-property-decorator'
import Form from '~/src/vform'
interface LoginForm {
email: string
password: string
}
@Component
export default class LoginView extends Vue {
form: Form<LoginForm> = new Form<LoginForm>({
email: '',
password: ''
})
async submit() {
await this.form.post('/auth/login')
}
}
这有效,在功能上,我可以填写表格并将数据提交到服务器。我遇到的问题是 Vue.js 中的反应性。因为属性在 Form
class 上不存在,数据不会传递给 v-model
,它只会在表单发生变化时在表单内部更新。
这不是问题,除非我在屏幕上显示表单中的数据。我现在可以忍受它,但我想知道是否有办法让 Vue 识别我的 Form
class 上的响应式属性,或者是否有更好的方法来实现此功能而不影响类型系统。
嗯,你的操作比vuejs自己做的高多了。 Vuejs 在 setter 中使用 Object.defineProperty 处理反应数据以重新渲染,但是,您提供了一个对象,该对象定义了其不可配置的属性,并且将无法触发 vuejs 的反应系统。
让它发挥作用:
export default class Form<Model> {
initialiseData(key) {
Object.defineProperty(this, key, {
get: () => this.data[key],
set: (value) => {
this.changes[key] = value
this.onChange(key, value)
},
})
}
onChange(key, value) {}
}
import _Form from '~/src/vform'
@Component
export default class LoginView extends Vue {
form: any = {}
// Lifecycle hook
mounted() {
const vm = this
class Form extends _Form {
onChange() {
vm.$forceUpdate()
}
}
const form = new Form({
email: '',
password: ''
})
this.$set('form', form)
}
}
通知vm.$forceUpdate
当你的表单属性改变时通知vuejs重新渲染。
我正在 TypeScript 中创建一个 class 来处理我的表单提交和服务器错误:
export default class Form<Model> {
private readonly original: Model
private changes: Partial<Model>
constructor(data: Model) {
this.original = data
Object.keys(this.original).forEach(key => this.initialiseData(key))
}
private initialiseData(key) {
Object.defineProperty(this, key, {
get: () => this.data[key],
set: (value) => this.changes[key] = value
}
}
get data(): Model {
return Object.assign({}, this.original, this.changes)
}
post(url: string) {
// post logic
}
}
这将在我的 Vue 组件中使用,如下所示:
import { Component, Vue } from 'vue-property-decorator'
import Form from '~/src/vform'
interface LoginForm {
email: string
password: string
}
@Component
export default class LoginView extends Vue {
form: Form<LoginForm> = new Form<LoginForm>({
email: '',
password: ''
})
async submit() {
await this.form.post('/auth/login')
}
}
这有效,在功能上,我可以填写表格并将数据提交到服务器。我遇到的问题是 Vue.js 中的反应性。因为属性在 Form
class 上不存在,数据不会传递给 v-model
,它只会在表单发生变化时在表单内部更新。
这不是问题,除非我在屏幕上显示表单中的数据。我现在可以忍受它,但我想知道是否有办法让 Vue 识别我的 Form
class 上的响应式属性,或者是否有更好的方法来实现此功能而不影响类型系统。
嗯,你的操作比vuejs自己做的高多了。 Vuejs 在 setter 中使用 Object.defineProperty 处理反应数据以重新渲染,但是,您提供了一个对象,该对象定义了其不可配置的属性,并且将无法触发 vuejs 的反应系统。
让它发挥作用:
export default class Form<Model> {
initialiseData(key) {
Object.defineProperty(this, key, {
get: () => this.data[key],
set: (value) => {
this.changes[key] = value
this.onChange(key, value)
},
})
}
onChange(key, value) {}
}
import _Form from '~/src/vform'
@Component
export default class LoginView extends Vue {
form: any = {}
// Lifecycle hook
mounted() {
const vm = this
class Form extends _Form {
onChange() {
vm.$forceUpdate()
}
}
const form = new Form({
email: '',
password: ''
})
this.$set('form', form)
}
}
通知vm.$forceUpdate
当你的表单属性改变时通知vuejs重新渲染。