我试图了解如何正确地观察一些道具变异。 我有一个父组件(.vue文件)从ajax调用接收数据,将数据放入一个对象并使用它通过v-for指令呈现一些子组件,简化我的实现:
<template>
<div>
<player v-for="(item, key, index) in players"
:item="item"
:index="index"
:key="key"">
</player>
</div>
</template>
...然后在<script>
标记内:
data(){
return {
players: {}
},
created(){
let self = this;
this.$http.get('../serv/config/player.php').then((response) => {
let pls = response.body;
for (let p in pls) {
self.$set(self.players, p, pls[p]);
}
});
}
项目对象是这样的:
item:{
prop: value,
someOtherProp: {
nestedProp: nestedValue,
myArray: [{type: "a", num: 1},{type: "b" num: 6} ...]
},
}
现在,在我的孩子&#34;播放器&#34;组件I试图查看任何项目的属性变化,我使用:
...
watch:{
'item.someOtherProp'(newVal){
//to work with changes in "myArray"
},
'item.prop'(newVal){
//to work with changes in prop
}
}
它有效,但对我来说似乎有点棘手,我想知道这是否是正确的方法。我的目标是每次prop
更改时执行某些操作,或myArray
获取新元素或在现有元素内部进行某些更改。任何建议将不胜感激。
答案 0 :(得分:381)
您可以使用deep watcher:
watch: {
item: {
handler(val){
// do stuff
},
deep: true
}
}
现在,这将检测item
数组中对象的任何更改以及对数组本身的添加(与Vue.set一起使用时)。这是一个JSFiddle:http://jsfiddle.net/je2rw3rs/
修改强>
如果您不想观察顶级对象的每个更改,并且只想要一个不那么笨拙的语法来直接观看嵌套对象,您只需观看computed
而不是:
var vm = new Vue({
el: '#app',
computed: {
foo() {
return this.item.foo;
}
},
watch: {
foo() {
console.log('Foo Changed!');
}
},
data: {
item: {
foo: 'foo'
}
}
})
这是JSFiddle:http://jsfiddle.net/oa07r5fw/
答案 1 :(得分:270)
另一个更好的方法和更优雅的方法如下:
watch:{
'item.someOtherProp': function (newVal, oldVal){
//to work with changes in someOtherProp
},
'item.prop': function(newVal, oldVal){
//to work with changes in prop
}
}
(我在comment here)
中从@peerbolte学到了这种方法答案 2 :(得分:8)
我发现它也可以这样工作:
watch: {
"details.position"(newValue, oldValue) {
console.log("changes here")
}
},
data() {
return {
details: {
position: ""
}
}
}
答案 3 :(得分:5)
另一种方法。
请勿使用箭头功能。您无法访问此对象。
watch:{
'item.someOtherProp': function(newValue, oldValue){
// Process
}
}
答案 4 :(得分:4)
如果您想看一会儿财产然后不看它怎么办?
还是要观看库子组件属性?
您可以使用“动态观察器”:
this.$watch(
'object.property', //what you want to watch
(newVal, oldVal) => {
//execute your code here
}
)
$watch
返回一个取消监视功能,如果调用该功能,它将停止监视。
var unwatch = vm.$watch('a', cb)
// later, teardown the watcher
unwatch()
您还可以使用deep
选项:
this.$watch(
'someObject', () => {
//execute your code here
},
{ deep: true }
)
请确保查看to docs
答案 5 :(得分:4)
我个人更喜欢这种干净的实现:
map
答案 6 :(得分:3)
如果要观看列表中的所有项目并知道列表中的哪个项目已更改,则可以分别在每个项目上设置自定义观察程序,如下所示:
var vm = new Vue({
data: {
list: [
{name: 'obj1 to watch'},
{name: 'obj2 to watch'},
],
},
methods: {
handleChange (newVal, oldVal) {
// Handle changes here!
// NOTE: For mutated objects, newVal and oldVal will be identical.
console.log(newVal);
},
},
created () {
this.list.forEach((val) => {
this.$watch(() => val, this.handleChange, {deep: true});
});
},
});
如果您的列表不是立即填充的(例如在原始问题中),则可以将逻辑从created
中移到所需的位置,例如在.then()
块中。
如果您的列表本身更新为包含新的或已删除的项目,我将开发一种有用的模式,“浅”监视列表本身,并在列表更改时动态监视/取消监视项目:
// NOTE: This example uses Lodash (_.differenceBy and _.pull) to compare lists
// and remove list items. The same result could be achieved with lots of
// list.indexOf(...) if you need to avoid external libraries.
var vm = new Vue({
data: {
list: [
{name: 'obj1 to watch'},
{name: 'obj2 to watch'},
],
watchTracker: [],
},
methods: {
handleChange (newVal, oldVal) {
// Handle changes here!
console.log(newVal);
},
updateWatchers () {
// Helper function for comparing list items to the "watchTracker".
const getItem = (val) => val.item || val;
// Items that aren't already watched: watch and add to watched list.
_.differenceBy(this.list, this.watchTracker, getItem).forEach((item) => {
const unwatch = this.$watch(() => item, this.handleChange, {deep: true});
this.watchTracker.push({ item: item, unwatch: unwatch });
// Uncomment below if adding a new item to the list should count as a "change".
// this.handleChange(item);
});
// Items that no longer exist: unwatch and remove from the watched list.
_.differenceBy(this.watchTracker, this.list, getItem).forEach((watchObj) => {
watchObj.unwatch();
_.pull(this.watchTracker, watchObj);
// Optionally add any further cleanup in here for when items are removed.
});
},
},
watch: {
list () {
return this.updateWatchers();
},
},
created () {
return this.updateWatchers();
},
});
答案 7 :(得分:2)
这里没有看到它,但是如果您扩展render() {
const { data } = this.state;
const allObj = { value: 'all', label: 'All' };
return (
<div>
<div className="grid-wrapper">
<div className="toolbar-sections comments">
<Select
id="selectStage"
getOptionLabel={(option) => 'Stage: ' + option.label}
className="toolbar-select"
options={this.state.optionsStages}
onChange={(value) => { this.handleDropDownChange(value, 'selectedStage') }}
placeholder="Stages"
isSearchable={false}
defaultValue={allObj}
/>
</div>
<ReactTable
filtered={this.state.filtered}
defaultFilterMethod={(filter, row) =>
String(row[filter.id]) === filter.value}
data={data}
onFilteredChange={this.onFilteredChange.bind(this)}
columns={[
{
Header: "Author",
id: "author",
accessor: "author",
width: 170,
Cell: row => {
return (
<span>
{row.value}
</span>
);
}
},
{
Header: "Subject",
accessor: "subject",
Cell: row => (
<span>
<span><a href="#">{row.value}...</a></span>
</span>
)
},
{
Header: "Stage",
accessor: "stage",
width: 150
}
]}
defaultPageSize={10}
className="-highlight"
/>
<br />
</div>
</div>
);
}
}
export default withRouter(CommentsTableComponent);
类,也可以使用vue-property-decorator
模式。
Vue
答案 8 :(得分:2)
对我来说,答案都没有奏效。实际上,如果您想监视嵌套数据,并且组件被多次调用。因此,它们被用不同的道具来识别。
例如let indexLat = locationString.index(locationString.startIndex, offsetBy: 8)
let indexLong = locationString.index(indexLat, offsetBy: 9)
let lat = String(locationString[locationString.startIndex..<indexLat])
let long = String(locationString[indexLat..<indexLong])
if let lattitude = Double(lat), let longitude = Double(long) {
let location = CLLocation(latitude: lattitude, longitude: longitude)
}
我的解决方法是创建一个附加的vuex状态变量,我手动对其进行更新以指向最后更新的属性。
这是Vuex.ts的实现示例:
<MyComponent chart="chart1"/> <MyComponent chart="chart2"/>
在任何Component函数上更新商店:
export default new Vuex.Store({
state: {
hovEpacTduList: {}, // a json of arrays to be shared by different components,
// for example hovEpacTduList["chart1"]=[2,6,9]
hovEpacTduListChangeForChart: "chart1" // to watch for latest update,
// here to access "chart1" update
},
mutations: {
setHovEpacTduList: (state, payload) => {
state.hovEpacTduListChangeForChart = payload.chart // we will watch hovEpacTduListChangeForChart
state.hovEpacTduList[payload.chart] = payload.list // instead of hovEpacTduList, which vuex cannot watch
},
}
现在在任何组件上获取更新:
const payload = {chart:"chart1", list: [4,6,3]}
this.$store.commit('setHovEpacTduList', payload);
答案 9 :(得分:1)
我对使用deep: true
的答案的问题是,在深入观察数组时,我不容易确定哪个元素包含更改。我找到的唯一明确的解决方案是this answer, which explains how to make a component so you can watch each array element individually.
答案 10 :(得分:1)
VueJ深入观察子对象
new Vue({
el: "#myElement",
data: {
entity: {
properties: []
}
},
watch: {
'entity.properties': {
handler: function (after, before) {
// Changes detected. Do work...
},
deep: true
}
}
});
答案 11 :(得分:0)
我用来“破解”此解决方案的另一种添加方法是:
我设置了一个单独的computed
值,该值将简单地返回嵌套对象的值。
data : function(){
return {
my_object : {
my_deep_object : {
my_value : "hello world";
}.
},
};
},
computed : {
helper_name : function(){
return this.my_object.my_deep_object.my_value;
},
},
watch : {
helper_name : function(newVal, oldVal){
// do this...
}
}
答案 12 :(得分:0)
我使用了 deep:true,但发现监视函数中的旧值和新值始终相同。作为先前解决方案的替代方案,我尝试了此方法,它将通过将其转换为字符串来检查整个对象中的任何更改:
created() {
this.$watch(
() => JSON.stringify(this.object),
(newValue, oldValue) => {
//do your stuff
}
);
},
答案 13 :(得分:-1)
这是一种为嵌套属性编写观察程序的方法:
new Vue({
...allYourOtherStuff,
watch: {
['foo.bar'](newValue, oldValue) {
// Do stuff here
}
}
});
您甚至可以将此语法用于异步观察程序:
new Vue({
...allYourOtherStuff,
watch: {
async ['foo.bar'](newValue, oldValue) {
// Do stuff here
}
}
});