0👍
Try this:
let computed;
let list = ["exp", "fund"];
this.$emit = (s, value) => {
let key = Object.keys(value)[0];
this.job[key] = value[key];
}
this.job = {
exp: 20
}
list.map((v) => {
computed = {
...computed,
[v]: {
get: () => {
return this.job[v];
},
set: (value) => {
return this.$emit('job', { [v]: value });
}
}
}
})
console.log("get", computed.exp.get());
computed.exp.set(10);
console.log("get", computed.exp.get());
- [Vuejs]-If CORS if refusing my API request and I don't control the server, is there nothing I can do?
- [Vuejs]-How to assign A block of JavaScript code in a JavaScript variable?
0👍
You can use the $watch
api with the deep: true
option. Here’s a basic implementation with an increment function:
new Vue({
el: "#app",
data: {
job: {
a: 11,
b: 22,
c: 33,
d: 44,
e: 55,
f: 66,
g: 77,
h: 88,
// ...
},
},
created() {
// use $watch interface with the deep option
this.$watch('job', (newVal, oldVal) => {
// check for changes from the previous state
Object.keys(newVal).forEach(key => {
if(newVal[key] !== oldVal[key]) {
console.log('changed job attr', key, newVal[key])
this.$emit('job', {[key]: newVal[key]})
}
})
}, {deep: true})
},
methods: {
increment(key) {
// needs to be reassigned rather than mutated if you want
// the $watch callback to get the correct oldVal
const val = this.job[key] + 1
this.job = Object.assign({}, this.job, {[key]: val})
}
},
})
html to demo the increment function:
<div id="app">
<ul>
<li v-for="(val, key) in job" :key="key" @click="increment(key)">
{{ key }}: {{ val }}
</li>
</ul>
</div>
0👍
I assume you’re using the get
/set
approach so that you can use v-model
. Personally I would probably ditch the v-model
and use the separate prop/event pair.
However, that isn’t to say that generating repeated computed properties cannot be done:
const properties = ['exp', 'fund']
const computed = {}
for (const property of properties) {
computed[property] = {
get () {
return this.job[property]
},
set (value) {
this.$emit('job', { [property]: value })
}
}
}
const Child = {
template: `
<div>
<input v-model="exp">
<input v-model="fund">
</div>
`,
props: ['job'],
computed: {
...computed
// other computed properties here
}
}
new Vue({
el: '#app',
components: {
Child
},
data () {
return {
job: {
exp: 'hello',
fund: 'goodbye'
}
}
},
methods: {
updateJob (changes) {
for (const property in changes) {
this.$set(this.job, property, changes[property])
}
}
}
})
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<div id="app">
<Child :job="job" @job="updateJob"></Child>
<pre>{{ job }}</pre>
</div>
Each computed property just needs an object with a get
and set
method. It’s important to realise that these are not get
and set
in the defineProperty
sense. Instead they are just normal methods that happen to be called get
and set
.
We need one such object for each computed property, so we create them in a loop and add them all to an object (which I’ve called computed
) that holds all of these computed properties.
Then, in the component definition, these properties are spread using the ...
operator. Strictly speaking the spreading isn’t necessary unless there are other computed properties that aren’t present in that object.
You could move all of the code for building the computed properties inline under the computed
property, rather than having it at the start. There are two ways to do that, either by using reduce
or by wrapping it all in an IIFE than returns the relevant object. To my mind that would look a bit unwieldy so I’ve kept it outside instead.
- [Vuejs]-Vue.js: v-for behaves different with template literals
- [Vuejs]-Vue JS Multiple filters, one array