ChatGPT解决这个技术问题 Extra ChatGPT

如何监听“道具”的变化

VueJs 2.0 docs 中,我找不到任何可以监听 props 更改的挂钩。

VueJs 是否有像 onPropsUpdated() 或类似的钩子?

更新

正如@wostex 建议的那样,我尝试watch我的财产,但没有任何改变。然后我意识到我有一个特殊情况:

<template>
    <child :my-prop="myProp"></child>
</template>

<script>
   export default {
      props: ['myProp']
   }
</script>

我将父组件接收到的 myProp 传递给 child 组件。然后 watch: {myProp: ...} 不工作。

@wostex,这里是 CodePen。坏事是它在笔里工作......

E
Egor Stambakio

您可以 watch props 在 props 更改时执行一些代码:

new Vue({ el: '#app', data: { text: 'Hello' }, components: { 'child' : { template: `

{{ myprop }}

`, props: [' myprop'], watch: { myprop: function(newVal, oldVal) { // 观看 console.log('Prop changed: ', newVal, ' | was: ', oldVal) } } } } });


我知道不鼓励使用 watch,因为使用计算属性通常会更好,但是使用 watch 是否有任何性能问题?
@SethWhite 根据我对 reactivity is handled in Vue 如何使用观察者模式的理解,观察者不一定比计算数据或其他反应性数据效率低。在一个属性的值依赖于许多值的情况下,计算的 prop 将为结果所依赖的每个值运行一个单独的函数而不是一个单独的监视回调。我认为在最常见的用例中,计算属性会产生所需的结果。
对于希望使用类(例如在打字稿中)执行此操作的任何人,请查看 this answer
如果道具发生变化而不是使用观察者,不应该使用道具重新渲染吗?
我在看道具的时候在手表部分看到了一个没有键的符号。只有一个功能。有没有关于这个 notaton 的文档(vue 2)?
t
tony19

你试过这个吗?

watch: {
  myProp: {
    // the callback will be called immediately after the start of the observation
    immediate: true, 
    handler (val, oldVal) {
      // do your stuff
    }
  }
}

https://v2.vuejs.org/v2/api/#watch


这对我有用,但如果能解释为什么它会起作用,那会很有帮助。
t
tony19

就我而言,我需要一个解决方案,任何时候任何道具都会发生变化,我需要再次解析我的数据。我厌倦了为我的所有道具制作单独的观察者,所以我使用了这个:

  watch: {
    $props: {
      handler() {
        this.parseData();
      },
      deep: true,
      immediate: true,
    },
  },

从这个例子中得到的关键点是使用 deep: true,所以它不仅监视 $props,而且还监视嵌套值,例如 props.myProp

您可以在此处了解有关此扩展观看选项的更多信息:https://v2.vuejs.org/v2/api/#vm-watch


这应该被标记为答案,因为它是设置深度对象监视以观察其属性更改的适当方法。
谢谢,我想现在我们可以投票了。或者OP可以改变它
欣赏!这就是我一直在寻找的。
A
Ankit Kumar Ojha

您需要了解您拥有的组件层次结构以及您如何传递道具,您的情况绝对是特殊的,开发人员通常不会遇到。

父组件 -myProp-> 子组件 -myProp-> 孙子组件

如果 myProp 在父组件中发生更改,它也会反映在子组件中。

如果 myProp 在子组件中发生更改,它也会反映在孙子组件中。

因此,如果 myProp 在父组件中发生更改,那么它将反映在孙子组件中。 (到目前为止,一切都很好)。

因此,在您不必做任何事情的层次结构中,道具本质上是被动的。

现在谈论等级上升

如果 myProp 在 grandChild 组件中发生更改,它将不会反映在子组件中。您必须在 child 中使用 .sync 修饰符并从 grandChild 组件发出事件。

如果 myProp 在子组件中发生更改,它将不会反映在父组件中。您必须在父组件中使用 .sync 修饰符并从子组件发出事件。

如果 myProp 在 grandChild 组件中更改,它将不会反映在父组件中(显然)。您必须使用 .sync 修饰符 child 并从孙子组件发出事件,然后观察子组件中的 prop 并在更改时发出一个事件,该事件正在由使用 .sync 修饰符的父组件侦听。

让我们看一些代码以避免混淆

父.vue

<template>
    <div>
    <child :myProp.sync="myProp"></child>
    <input v-model="myProp"/>
    <p>{{myProp}}</p>
</div>
</template>

<script>

    import child from './Child.vue'

    export default{
        data(){
            return{
                myProp:"hello"
            }
        },
        components:{
            child
        }
    }
</script>

<style scoped>
</style>

孩子.vue

<template>
<div>   <grand-child :myProp.sync="myProp"></grand-child>
    <p>{{myProp}}</p>
</div>

</template>

<script>
    import grandChild from './Grandchild.vue'

    export default{
        components:{
            grandChild
        },
        props:['myProp'],
        watch:{
            'myProp'(){
                this.$emit('update:myProp',this.myProp)

            }
        }
    }
</script>

<style>

</style>

孙子.vue

<template>
    <div><p>{{myProp}}</p>
    <input v-model="myProp" @input="changed"/>
    </div>
</template>

<script>
    export default{
        props:['myProp'],
        methods:{
            changed(event){
                this.$emit('update:myProp',this.myProp)
            }
        }
    }
</script>

<style>

</style>

但是在此之后,您将不会注意到 vue 的尖叫警告说

'避免直接改变道具,因为每当父组件重新渲染时,该值都会被覆盖。

同样,正如我之前提到的,大多数开发人员都不会遇到这个问题,因为它是一种反模式。这就是您收到此警告的原因。

但是为了解决你的问题(根据你的设计)。我相信你必须做上述工作(老实说,hack)。我仍然建议你应该重新考虑你的设计,并且使错误更不容易出现。

我希望它有所帮助。


t
tony19

对于两种方式绑定,您必须使用 .sync 修饰符

<child :myprop.sync="text"></child>

more details...

并且您必须在子组件中使用 watch 属性来监听和更新任何更改

props: ['myprop'],
  watch: { 
    myprop: function(newVal, oldVal) { // watch it
      console.log('Prop changed: ', newVal, ' | was: ', oldVal)
    }
  }

m
m.cichacz

不确定您是否已解决(如果我理解正确),但这是我的想法:

如果父母收到 myProp,并且您希望它传递给孩子并在孩子中观看,那么父母必须拥有 myProp 的副本(而不是参考)。

尝试这个:

new Vue({
  el: '#app',
  data: {
    text: 'Hello'
  },
  components: {
    'parent': {
      props: ['myProp'],
      computed: {
        myInnerProp() { return myProp.clone(); } //eg. myProp.slice() for array
      }
    },
    'child': {
      props: ['myProp'],
      watch: {
        myProp(val, oldval) { now val will differ from oldval }
      }
    }
  }
}

在html中:

<child :my-prop="myInnerProp"></child>

实际上,在这种情况下处理复杂的集合时必须非常小心(传递几次)


W
Wouter Schoofs

我使用计算属性,例如:

    items:{
        get(){
            return this.resources;
        },
        set(v){
            this.$emit("update:resources", v)
        }
    },

在这种情况下,资源是一个属性:

props: [ 'resources' ]

H
Heroselohim

道具和 v-model 处理。如何将值从父级传递给子级,从子级传递给父级。

手表不是必需的!在 Vue 中改变 props 也是一种反模式,因此您永远不应该更改子组件或组件中的 prop 值。使用 $emit 更改值,Vue 将始终按预期工作。

/* 组件 - 孩子 */ Vue.component('props-change-component', { props: ['value', 'atext', 'anumber'],mounted() { var _this = this this.$emit(" update:anumber", 6) setTimeout(function () { // 更新父绑定变量为 'atext' _this.$emit("update:atext", "4s delay update from child!!") }, 4000) setTimeout (function () { // 更新父绑定的 v-model 值 _this.$emit("input", "6s delay update v-model value from child!!") }, 6000) }, template: '

\ v-model value: {{ value }}
\ atext: {{ atext }}
\ anumber: {{ anumber }}
\
' }) /* MAIN - PARENT * / const app = new Vue({ el: '#app', data() { return { myvalue: 7, mynumber: 99, mytext: "我自己的文本", } },mounted() { var _this = this //直接更新我们的变量 setTimeout(function () { _this.mytext = "2s delay update mytext from parent!!" }, 2000) }, })


该行: this.$emit("anumber", 6) 应该是: this.$emit("update:anumber", 6) ;除此之外,感谢您提供这个非常有用的答案;我特别看重你如何显示观看不是必需的! :)
M
Manuel Alanis

对我来说,这是一种礼貌的解决方案,可以获取一个特定的 prop(s) 更改并使用它创建逻辑

在接收更改后,我将使用 props 和变量 computed 属性创建逻辑

export default {
name: 'getObjectDetail',
filters: {},
components: {},
props: {
  objectDetail: { // <--- we could access to this value with this.objectDetail
    type: Object,
    required: true
  }
},
computed: {
  _objectDetail: {
    let value = false
    // ...
    // if || do || while -- whatever logic
    // insert validation logic with this.objectDetail (prop value)
    value = true
    // ...
    return value 
  }
}

所以,我们可以在 html 渲染上使用 _objectDetail

<span>
  {{ _objectDetail }}
</span>

或以某种方式:

literallySomeMethod: function() {
   if (this._objectDetail) {
   ....
   }
}

I
Ilyich

我认为在大多数情况下,Vue 在 prop 更改时更新组件的 DOM。

如果这是您的情况,那么您可以使用 beforeUpdate()updated() 钩子 (docs) 来观看道具。

如果您只对 newVal 感兴趣而不需要 oldVal,则可以这样做

new Vue({ el: '#app', data: { text: '' }, components: { 'child': { template: `

{{ myprop }}

`, props: ['myprop '], beforeUpdate() { console.log(this.myprop) }, updated() { console.log(this.myprop) } } } });


V
Valentine Shi

一些用例的有趣观察。

如果您通过道具从商店中观看数据项,并且您在同一个商店突变中多次更改数据项,它将不会被观看。

但是,如果您将数据项更改分成多个相同突变的调用,它将被监视。

此代码不会触发观察者: // 代码中的某处: this.$store.commit('changeWatchedDataItem'); // 在 'changeWatchedDataItem' 突变中: state.dataItem = false; state.dataItem = 真;

此代码将在每次突变时触发观察者: // 代码中的某处: this.$store.commit('changeWatchedDataItem', true); this.$store.commit('changeWatchedDataItem', false); // 在“changeWatchedDataItem”突变中:changeWatchedDataItem(state, newValue) { state.dataItem = newValue; }


K
Kiran Mahale

如果有人使用带有组合 API 的 Vue 2,我的以下答案是适用的。所以设置功能将是

setup: (props: any) => {
  watch(() => (props.myProp), (updatedProps: any) => {
    // you will get the latest props into updatedProp
  })
}

但是,您需要从组合 API 中导入 watch 函数。


k
kshitij

默认情况下,组件中的 props 是响应式的,您可以在组件内的 props 上设置 watch,这将帮助您根据需要修改功能。这是一个简单的代码片段来展示它是如何工作的

setup(props) {
 watch(
  () => props.propName,
  (oldValue, newValue) => {
    //Here you can add you functionality 
    // as described in the name you will get old and new value of watched property
  },
  { deep: true },
  { immediate: true } //if you need to run callback as soon as prop changes
)
}

希望这可以帮助你得到你想要的结果。祝你有美好的一天。


C
Cong Nguyen

监视功能应放在子组件中。不是父母。


R
Rahul Sharma

您可以使用监视模式来检测更改:

在原子级别上做所有事情。所以首先检查 watch 方法本身是否被调用,通过安慰里面的东西。一旦确定手表正在被调用,就用你的业务逻辑将其粉碎。

watch: { 
  myProp: function() {
   console.log('Prop changed')
  }
}

M
Manuel Alanis

如果我需要在接收更改后创建逻辑,我会使用 props 和 variables computed 属性

export default {
name: 'getObjectDetail',
filters: {},
components: {},
props: {
    objectDetail: {
      type: Object,
      required: true
    }
},
computed: {
    _objectDetail: {
        let value = false
        ...

        if (someValidation)
        ...
    }
}


A
Alvin Smith

@JoeSchr 有答案。如果您不想要deep: true,这是另一种方法

 mounted() {
    this.yourMethod();
    // re-render any time a prop changes
    Object.keys(this.$options.props).forEach(key => {
      this.$watch(key, this.yourMethod);
    });
  },

M
Max

如果你的道具 myProp 有嵌套的项目,那些嵌套的将不会是反应性的,所以你需要使用类似 lodash deepClone 的东西:

<child :myProp.sync="_.deepClone(myProp)"></child>

就是这样,不需要观察者或其他任何东西。


在这种情况下,您应该使用 myProp = Object.assign({}, newValue); 更新 myProp
a
adocking

如果 myProp 是一个对象,它通常不会被改变。所以,手表永远不会被触发。 myProp 没有被改变的原因是你在大多数情况下只是设置了 myProp 的一些键。 myProp 本身仍然是一个。尝试观看 myProp 的道具,例如“myProp.a”,它应该可以工作。


u
user229044

如果您添加,道具将发生变化

<template>
<child :my-prop="myProp"/>
</template>

<script>
export default {
   props: 'myProp'
}
</script>