如何将数据存储在自定义Vue组件而不是根Vue实例中?

时间:2019-05-29 20:08:19

标签: vue.js vuejs2 vue-component

我正在Vue中创建一个自定义复选框组件,并且可以与存储在根实例中的数据一起正常工作。我计划在多种情况下重用此组件(以及我正在构建的许多其他组件)。我不需要每次使用组件时都必须更新或编辑根Vue实例,并且只希望将数据存储在组件本身中。选中/未选中的布尔值必须是反应性的。

我尝试使用计算值,但也无法正常工作。我愿意在需要时使用它。

(此版本无效)

<body>
  <script src="https://unpkg.com/vue@2.6.10"></script>
  <div id="app">
    <checkbox-item v-model="checkData">Active</checkbox-item>
    {{ checkData }}
  </div>
</body>

</html>

<script>
  Vue.component('checkbox-item', {
    template: `
          <label class="checkbox-item">
            <input type="checkbox" :checked="value"
                   @change="$emit('input', $event.target.checked)"
                   class="checkbox-input">
            <span class="checkbox-label">
              <slot></slot>
            </span>
          </label>
        `,
    data: function() {
      return {
        checkData: null
      }
    },
    props: ['value']
  })
  new Vue({
    el: '#app',
  })
</script>

(此版本有效,但我仍然需要数据不在根实例中)

<body>
  <script src="https://unpkg.com/vue@2.6.10"></script>
  <div id="app">
    <checkbox-item v-model="checkData">Active</checkbox-item>
    {{ checkData }}
  </div>
</body>

<script>
  Vue.component('checkbox-item', {
    template: `
          <label class="checkbox-item">
            <input type="checkbox" :checked="value"
                   @change="$emit('input', $event.target.checked)"
                   class="checkbox-input">
            <span class="checkbox-label">
              <slot></slot>
            </span>
          </label>
        `,
    props: ['value']
  })
  new Vue({
    el: '#app',
    data: {
      checkData: null
    }
  })
</script>

我得到的错误是:

  

[Vue警告]:属性或方法“ checkData”未在实例上定义,但在渲染期间被引用。通过初始化属性,确保在data选项中或对于基于类的组件,此属性都是反应性的。参见:https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties

checkData不像在工作示例中那样被动。

编辑:好的,这是可行的!我肯定会研究使用SFC和其他代码组织方法,但目前它仍在一个html文件中。有没有人看到从长远来看这是行不通的原因?

  <body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <div id="app">
        <checkbox-item></checkbox-item>
    </div>
  </body>
</html>

<script>
  Vue.component('checkbox-item', {
    template: `
      <label class="checkbox-item">
        <input type="checkbox" v-model="checkData"
               class="checkbox-input">
        <span class="checkbox-label">
          <slot>Active: {{checkData}}</slot>
        </span>
      </label>
    `,
    data: function(){
      return {
        checkData: this.checked
      }
    },
  })
  new Vue({
    el: '#app',
  })
</script>

1 个答案:

答案 0 :(得分:1)

第一个示例不起作用的原因是因为您的Vue根组件无权访问复选框的数据。

<html>
<!-- Your existing nonfunctional example -->
<body>
  <script src="https://unpkg.com/vue@2.6.10"></script>
  <div id="app">
    <!-- Both v-model and {{ checkData }}
      are asking about the root vue's checkData,
      but you took that off. This is why you have an error -->
    <checkbox-item v-model="checkData">Active</checkbox-item>
    {{ checkData }}
  </div>
</body>

</html>

非功能示例中发生了什么?

在非功能示例中,当您说v-model="checkData"时,这是在告诉父(根)Vue组件在其本地范围内找到checkData以及v-bind:value="checkData"v-on:input="checkData = $event.target.value"

使您的复选框项目可重复使用

您的组件可以很好地按原样重复使用。

我对您的checkbox-item所做的唯一更改是在v-on="$listeners"元素上传递v-bind="$attrs"input,并删除属性中的显式“值”

对于任何低级,可重用的UI组件,您都需要输入和输出数据。使用v模型并将数据存储在父组件中实际上是您想要做的。将数据存储在根组件中感觉很笨拙,因此通常存在中级组件。

为了证明这一点,我列出了一个可以高兴或难过的书呆子,并使用您的复选框更新了他们的状态。

Root Vue组件中的用法
<body>
  <script src="https://unpkg.com/vue@2.6.10"></script>
  <div id="app">
    <!-- If you wanted to take in data,
        you would pass in the nerds array as a Prop
        into nerd-list _from_ the root Vue instance -->
    <nerd-list/> 
  </div>
</body>

<script>
  Vue.component('nerd-list', {
   template: '<div>
     <h1>List of nerds and if they are happy</h1>
     <div v-for="nerd in nerds" :key="nerd.id">
       {{ nerd.name }}
       <checkbox-item v-model="nerd.happy">Happy</checkbox-item>
     </div>
   </div>',
  data() {
    return {
      nerds: [
        { name: 'Jess', happy: true, id: 1 },
        { name: 'Tiffany', happy: true, id: 2 },
      ]
    };
  },
});

  Vue.component('checkbox-item', {
    template: `
          <label class="checkbox-item">
            <input type="checkbox" :checked="value"
                   @change="$emit('input', $event.target.checked)"
                   class="checkbox-input">
            <span class="checkbox-label">
              <slot></slot>
            </span>
          </label>
        `,
    props: ['value']
  })
  new Vue({
    el: '#app',
    data: {}, // any data in here could be used to pass props into the nerd-list.
  })
</script>

最后,如您所知,将所有这些内容都写到Javascript文件中似乎有些麻烦。我强烈建议使用Vue CLI和Vue SFC组件以获得更好的体验。