【问题标题】:Trying to bind props to v-model尝试将道具绑定到 v-model
【发布时间】:2018-03-07 08:38:36
【问题描述】:

我正在使用 vuetify.js 并尝试创建一个可在整个应用程序中重复使用的组件。虽然它工作得很好,但我不确定它是否是正确的方法。

我正在创建一个导航抽屉组件,它始终具有相同的菜单选项,但可以从 UI 元素中打开。

下面是代码。

// NavigationBar.vue

<template>
  <v-navigation-drawer
    temporary
    v-model="drawerFlag"
    light
    overflow
    fixed
  >
    <v-list>
      <v-list-tile>
        <v-list-tile-action @click.stop="toggleDrawer()">
          <v-btn icon>
            <v-icon>close</v-icon>
          </v-btn>
        </v-list-tile-action>
      </v-list-tile>
    </v-list>
    <v-list class="pt-0">
      <template v-for="item in items">
        <v-list-tile :key="item.title" :to="item.link">
          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title>{{ item.title }}</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
        <v-divider></v-divider>
      </template>
    </v-list>
  </v-navigation-drawer>
</template>

<script>
  export default {
    props: ['drawer'],
    data() {
      return {
        items: [
          { title: 'Home', icon: 'home', link: '/home'},
          { title: 'History', icon: 'history', link: '/history' },
          { title: 'Wallet', icon: 'account_balance_wallet', link: '/wallet' },
          { title: 'My Profile', icon: 'person', link: '/profile' },
          { title: 'Settings', icon: 'settings', link: '/settings' },
          { title: 'About', icon: 'error', link: '/about' },
          { title: 'Logout', icon: 'power_settings_new', link: '/logout' },
        ]
      };
    },
    computed: {
      drawerFlag: {
        get: function() {
          return this.drawer
        },
        set: function() {

        }
      }
    },
    methods: {
      toggleDrawer: function() {
        this.$emit('emitToggleDrawer');
      }
    }
  }
</script>

//Home.vue

<template>
  <div class="full-screen">
    <navigation-bar :drawer="drawer" v-on:emitToggleDrawer="toggleDrawer"></navigation-bar>
    <v-btn icon class="mt-3 fixed-position" @click.stop="drawer = !drawer">
      <v-icon>menu</v-icon>
    </v-btn>
  </div>
</template>

<script>
  export default {
    name: 'home',
    data() {
      return {
        drawer: null
      };
    },

    computed: {
      user() {
        return this.$store.getters.user;
      }

    },

    methods: {
      toggleDrawer: function () {
        this.drawer = !this.drawer;
      }
    }
  };
</script>

在上面的代码中..

在父组件中,我有打开导航抽屉的按钮,导航抽屉的状态在称为“抽屉”的父组件中维护。然后,我将“抽屉”作为道具传递给子组件,并传递一个方法来触发从子组件到父组件的事件,称为“emitToggleDrawer”。

在子组件中,我使用的是 vuetify.js 导航抽屉,它采用 v-model="drawerFlag",其中drawerFlag 是一个计算属性。当我尝试使用 v-model="drawer" 即绑定到道具时出现错误。然后我们可以通过单击导航抽屉内的元素来关闭导航抽屉。为了实现这一点,我正在调用组件的一个方法,该方法稍后会发出一个由父组件监听的事件。

【问题讨论】:

  • 为什么要把'drawer'重新定义为'drawerFlag',因为它已经在Home.vue data()中注册了,你把它作为props提供给组件,你不能直接访问它吗作为“抽屉”?
  • 当我们尝试使用 v-model="drawer" 时,问题出在子组件中,然后它给出一个错误消息“避免直接改变道具,因为只要父组件重新设置,该值就会被覆盖-renders。相反,使用基于道具值的数据或计算属性。道具正在变异:“抽屉”“。
  • 所以另一种方法是在 NavigationBar.vue 中您也可以在 data() 中定义抽屉标志 rt?
  • 所以它可以自动附加getter和setter方法
  • 当你在数据中定义'drawerFlag'时,它只会在初始时间被设置。从父级更改“抽屉”时,它不会反映在数据属性中。

标签: javascript vue.js vuejs2 vuetify.js


【解决方案1】:

我是这样解决的:

App.vue

<my-drawer ref="drawer"></my-drawer>
<my-header @toggle-drawer="$refs.drawer.drawer = !$refs.drawer.drawer"></my-header>

MyDrawer.vue

<v-navigation-drawer v-model="drawer">
...
data() {
  drawer: true
}

MyHeader.vue

<v-toolbar-side-icon @click.stop="$emit('toggle-drawer')"></v-toolbar-side-icon>


在我看来,我们需要在自定义抽屉组件上使用v-model="drawer",以便它可以在所有屏幕尺寸上正常工作。

因此,我们还需要以某种方式从父级(或兄弟级)更改它的值,这就是我在抽屉组件上使用ref 的原因。 也许我可以调用抽屉函数而不是更改$refs.drawer.drawer 数据。我不确定有什么更好的方法。但这是唯一适用于所有屏幕尺寸的简单解决方案。

所以在我的情况下,我只从标题更改抽屉状态,但我认为您可以使用它并根据您的需要进行调整。

【讨论】:

    【解决方案2】:

    我解决了类似的问题,如下所示。

    • 只使用drawer 而不是使用drawerdrawerFlag
    • 子组件上没有额外的按钮
    • 不从子级向父级发送event
    • 在子组件中使用watch

    Home.Vue

    <template>
      <div class="full-screen">
        <navigation-bar :drawer="drawer"></navigation-bar>
        <v-btn icon class="mt-3 fixed-position" @click.stop="drawer = !drawer">
          <v-icon>menu</v-icon>
        </v-btn>
      </div>
    </template>
    
    <script>
      import NavigationBar from '@/components/NavigationBar';
      export default {
        name: 'home',
        data() {
          return {
            drawer: true
          };
        },
        components: {
          NavigationBar
        }
      }
    </script>
    

    NavigationBar.vue

    <template>
      <v-navigation-drawer
        temporary
        v-model="drawer"
        light
        overflow
        fixed
      >
        <v-list class="pt-0">
          <template v-for="item in items">
            <v-list-tile :key="item.title" :to="item.link">
              <v-list-tile-action>
                <v-icon>{{ item.icon }}</v-icon>
              </v-list-tile-action>
              <v-list-tile-content>
                <v-list-tile-title>{{ item.title }}</v-list-tile-title>
              </v-list-tile-content>
            </v-list-tile>
            <v-divider></v-divider>
          </template>
        </v-list>
      </v-navigation-drawer>
    </template>
    
    <script>
      export default {
        props: ['drawer'],
        data() {
          return {
            items: [
              { title: 'Home', icon: 'home', link: '/home'},
              { title: 'History', icon: 'history', link: '/history' },
              { title: 'Wallet', icon: 'account_balance_wallet', link: '/wallet' },
              { title: 'My Profile', icon: 'person', link: '/profile' },
              { title: 'Settings', icon: 'settings', link: '/settings' },
              { title: 'About', icon: 'error', link: '/about' },
              { title: 'Logout', icon: 'power_settings_new', link: '/logout' },
            ]
          };
        },
        watch: {
           drawer (value) {
              return value;
           }
        }
      }
    </script>
    

    【讨论】:

    • 您提供的解决方案不正确。你不应该直接修改道具。通过使用 v-model="drawer" 您正在绑定道具。在开发模式下运行 vue.js 时,您会在控制台中收到警告。
    猜你喜欢
    • 2018-07-29
    • 1970-01-01
    • 2017-07-26
    • 2019-06-16
    • 1970-01-01
    • 1970-01-01
    • 2016-05-14
    • 2018-03-07
    • 2021-03-07
    相关资源
    最近更新 更多