【问题标题】:Why must vue component data be a function?为什么vue组件数据必须是函数?
【发布时间】:2018-03-31 07:17:04
【问题描述】:

我正在阅读Vue components,发现他们对为什么 data 需要成为一个函数的解释有些混乱:

根实例

var vm = new Vue({
  el: '#example',
  data: {
    message: 'here data is a property'
  }
})

一个组件

var vm = new Vue({
  el: '#example',
  data: function () {
     return {
       counter: 0
     }
  }
})

Vue 文档通过为每个组件分配一个全局计数器变量来解释这种差异,然后他们对每个组件共享相同的数据感到惊讶......而且他们没有解释为什么他们已经在这里使用了一个函数。

var data = { counter: 0 }

Vue.component('simple-counter', {
  template: '<div>{{ counter }}</div >',
  data: function () {
    return data  
  }
})

当然现在共享数据

<simple-counter></simple-counter>
<simple-counter></simple-counter>
<simple-counter></simple-counter>

当您引用全局对象作为数据源时,组件没有自己的数据也就不足为奇了。对于将数据作为属性的根 Vue 实例也是如此。

var mydata = { counter: 0 }

var vm1 = new Vue({
  el: '#example1',
  data: mydata
})

var vm2 = new Vue({
  el: '#example2',
  data: mydata
})

所以我还有一个问题,为什么组件不能有数据属性?

【问题讨论】:

    标签: vue.js vuejs2


    【解决方案1】:

    据我了解,是为了节省内存

    许多框架,例如 Angular 2 或(有时)React,使组件的每个实例成为一个单独的对象。这意味着每个组件所需的一切都针对每个组件进行了初始化。不过,通常情况下,您实际上只需要在每次初始化时将组件的数据分开。方法等保持不变。

    Vue 通过将数据作为返回对象的函数来避免这个陷阱。这允许单独的组件具有单独的内部状态,而无需完全重新实例化整个组件。方法、计算属性定义和生命周期挂钩只创建和存储一次,并针对组件的每个实例运行。

    See this

    【讨论】:

    • 太棒了!当我开始学习 Vue 时,我也遇到了这个问题
    • 你能告诉我同一个组件怎么会有多个实例?有什么例子吗?甚至官方文件也将数据作为属性而不是功能。 vuejs.org/v2/guide/events.html#Listening-to-Events
    【解决方案2】:

    它必须是一个函数,否则数据将在组件的所有实例之间共享,因为对象是通过引用调用而不是通过值调用。这不仅会在您引用全局对象时发生,而且在数据是对象本身时也会发生。 如果 data 是返回对象的工厂函数,则每次挂载组件的新实例时都会从头开始创建该对象,而不是仅传递对全局数据的引用。

    【讨论】:

    • 当 data 的值是一个对象时,它在一个组件的所有实例之间共享......我们希望每个组件实例只管理自己的数据。为此,每个实例都必须生成一个唯一的数据对象。在 JavaScript 中,这可以通过在函数中返回对象来实现。来源:vuejs.org/v2/style-guide/#Component-data-essential
    【解决方案3】:

    data 选项应始终是组件上下文中的函数,该函数返回一个新对象。

    这个预防措施是vue做的。所以每当你直接在 data 选项中定义对象时,vue 都会发现错误。

    永远不允许组件直接改变其状态。这可以防止我们在组件没有自己的状态时搞砸和做坏事。

    如果 vue 没有采取这种预防措施,那么您将有机会改变该组件拥有的任何其他组件,这将是一个安全问题。

    来自documentation的示例:

    很高兴了解规则存在的原因,所以让我们作弊吧。

    <div id="example-2">
      <simple-counter></simple-counter>
      <simple-counter></simple-counter>
      <simple-counter></simple-counter>
    </div>
    var data = { counter: 0 }
    
    Vue.component('simple-counter', {
      template: '<button v-on:click="counter += 1">{{ counter }}</button>',
      // data is technically a function, so Vue won't
      // complain, but we return the same object
      // reference for each component instance
      data: function () {
        return data
      }
    })
    
    new Vue({
      el: '#example-2'
    })
    

    由于所有三个组件实例共享同一个数据对象,增加一个计数器会使它们全部增加!哎哟。让我们通过返回一个新的数据对象来解决这个问题:

    data: function () {
      return {
        counter: 0
      }
    }
    

    现在我们所有的计数器都有自己的内部状态。

    【讨论】:

    • 谢谢,这很有意义。我现在使用“vue-class-component”,这似乎抽象出了数据是一个函数的想法。类的所有属性都会自动转换为此函数,但您不需要自己定义。看起来像class Bla extends Vue { myproperty = "hello" }
    • 因为它是抽象的。你不能从外部改变它的数据。希望,这是有道理的。
    • 是的,我认为类组件使它比普通的 Vue 更安全,因为数据自动成为一个函数。
    • 是的,但是这里的数据不是函数而是类的成员。
    【解决方案4】:

    因为 Vue 初始化数据的时候,

    function initData(vm){
    
      let data = vm.$options.data
    
      data = vm._data = typeof data === ‘function’ ? getData(data, vm) : data || {}
       /*
    
         Because here,data is a reference from vm.$options.data, 
         if data is an object, 
         when there are many instances of this Component,
         they all use the same `data`
    
    
          if data is a function, Vue will use method getData( a wrapper to executing data function, adds some error handling)
    
          and return a new object, this object just belongs to current vm you are initializing
    
        */
    
       ……
    
    
      // observing data
      observe(data, true)
    
    }
    
    

    【讨论】:

      【解决方案5】:

      为什么 Vue 强制 data 属性是一个函数是组件的每个实例都应该有自己的数据对象。如果我们不这样做,所有实例将共享同一个对象,并且每次我们更改某些内容时,它都会反映在所有实例中。

      var vm = 新的 Vue({ el: '#example', **数据:函数(){ 返回 { 计数器:0 }** }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-27
        • 1970-01-01
        • 1970-01-01
        • 2019-12-01
        • 2013-12-16
        • 1970-01-01
        • 2021-12-31
        • 2017-09-18
        相关资源
        最近更新 更多