从路由器设置时道具未更新

Props not updated when set from router

当我在路由定义中设置组件 props 时,观察器不工作并且视图永远不会更新。

在此示例中,更新工作正常:

const Home = { template: '<div>Home</div>' }
const Test = {
template: '<div>Test : {{ nb }}<br><button @click="addOne" type="button">+1</button></div>',
props: {nb: Number},
methods: {
  addOne() {
    this.nb++
  }
}
}

const router = new VueRouter({
  routes: [
    { path: '/', component: Home },
    { name: 'test', path: '/test/:nb', component: Test, props: true }
  ]
})

new Vue({
 router,
  el: '#app'
})
<script src="https://npmcdn.com/vue/dist/vue.js"></script>
<script src="https://npmcdn.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <router-link to="/">/home</router-link>
  <router-link :to="{ name: 'test', params: { nb: 42 }}">/test</router-link>
  <router-view></router-view>
</div>

Note : This example show a "mutating a prop directly" warning, but it's just for the simplicity it's not related to the issue since I don't do that in my code.

在此示例中,更新不起作用:

const Home = { template: '<div>Home</div>' }
const Test = {
template: '<div>Test : {{ counter.value }}<br><button @click="addOne" type="button">+1</button></div>',
props: {counter: Object},
methods: {
  addOne() {
    this.counter.value++
    console.log('new value : ' + this.counter.value)
  }
}
}

class Counter {
  constructor(value) {
    this.value = value
  }
}

const router = new VueRouter({
  routes: [
    { path: '/', component: Home },
    {
      name: 'test',
      path: '/test/:nb',
      props: (route) => ({counter: new Counter(route.params.nb)}),
      component: Test
    }
  ]
})

new Vue({
 router,
  el: '#app'
})
<script src="https://npmcdn.com/vue/dist/vue.js"></script>
<script src="https://npmcdn.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <router-link to="/">/home</router-link>
  <router-link :to="{ name: 'test', params: { nb: 42 }}">/test</router-link>
  <router-view></router-view>
</div>

counter 对象不会反应,因此不会检测到 属性 更改。将对象作为 prop 传递不会增加反应性。

我刚刚在您的示例中更改了一行:

props: (route) => ({counter: Vue.observable(new Counter(route.params.nb))}),

将对象传递给 Vue.observable 将应用反应性。

请注意,'applying reactivity' 表示重写所有属性以使用 getter 和 setter。在此处提供的简单示例中,它仅表示 value 属性,应该没问题。 Vue 只能重写它可以看到的属性,因此无法访问隐藏在闭包中的任何数据。

const Home = { template: '<div>Home</div>' }
const Test = {
template: '<div>Test : {{ counter.value }}<br><button @click="addOne" type="button">+1</button></div>',
props: {counter: Object},
methods: {
  addOne() {
    this.counter.value++
    console.log('new value : ' + this.counter.value)
  }
}
}

class Counter {
  constructor(value) {
    this.value = value
  }
}

const router = new VueRouter({
  routes: [
    { path: '/', component: Home },
    {
      name: 'test',
      path: '/test/:nb',
      props: (route) => ({counter: Vue.observable(new Counter(route.params.nb))}),
      component: Test
    }
  ]
})

new Vue({
 router,
  el: '#app'
})
<script src="https://npmcdn.com/vue/dist/vue.js"></script>
<script src="https://npmcdn.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <router-link to="/">/home</router-link>
  <router-link :to="{ name: 'test', params: { nb: 42 }}">/test</router-link>
  <router-view></router-view>
</div>

Vue 不自动对作为 props 传递的对象应用反应性的部分原因是接收组件无论如何都不应该修改对象。这违反了单向数据流。在此示例中,您可能应该直接更新路由而不是修改 counter 对象。