重构vue单文件组件

Posted

技术标签:

【中文标题】重构vue单文件组件【英文标题】:Refactoring vue single file components 【发布时间】:2019-02-06 19:47:06 【问题描述】:

随着我的单个文件组件越来越大,我尝试对其进行一些重构。原来我有几个对话框使.vue 文件很大(800 行以上)。所以为了保持组件干净,我试图将对话框变成专用的子组件(mydialog)。我正在使用 vuetify(不需要熟悉 vuetify)。

我在父组件中有一个启用对话框的按钮。我将dialog 属性发送到子组件,然后将其附加到对话框的v-model。问题是,只能在第一次使用。这是因为当我单击close 按钮时,它会将dialog 的值更改为false,并且它永远保持false,因为子组件与父组件失去了通信。在这种情况下,我该如何解决这个问题?

这里是sn-p:

Vue.component('mydialog', 
  props:
    dialog: 
      type: Boolean,
      default: false
    
  ,

  template: `
<div class="text-xs-center">
    <v-dialog
      v-model="dialog"
      
    >

      <v-card>
        <v-card-title
          class="headline grey lighten-2"
          primary-title
        >
          A Dialog
        </v-card-title>

        <v-card-text>
          Lorem ipsum dolor sit amet,
        </v-card-text>

        <v-divider></v-divider>

        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn
            color="primary"
            flat
            @click="dialog = false"
          >
            Close
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>
`,
  data: function() 
    return 
      // dialog: false,
    
  

);

new Vue(
  el: '#app',
  data: 
    dialog: false
  

);
<!doctype html>
<html>

<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.css" />
</head>

<body>
  <div id="app">
    <v-app id="inspire">
      <v-btn color="red lighten-2" dark @click="dialog=true">Click Me</v-btn>
      <mydialog :dialog="dialog"></mydialog>
    </v-app>

  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.js"></script>
</body>

</html>

【问题讨论】:

看起来像 this one 的副本。 【参考方案1】:

您的组件通信有点偏离:基本上您的对话框没有通知应用程序组件它已关闭。以下两个更改启用了 modal 和 app 之间的上游通信:

app 模板中:

  <mydialog :dialog.sync="dialog"></mydialog>

mydialog 控制器中:

data: function() 
    return 
      dialog$: false,
    ;
  ,
  methods: 
    onClose() 
      this.dialog$ = false;
      this.$emit('update:dialog', this.dialog$);
    ,
  ,
  watch: 
    dialog: 
      immediate: true,
      handler() 
        this.dialog$ = this.dialog;
      ,
    ,
  

第一个更改使app 组件侦听mydialogdialog 属性的更新。

mydialog 中,我添加了一个数据属性dialog$,它反映了dialog 道具(因为道具被认为是恒定的,不应更改)。观察者负责dialog 上的下游更新更新dialog$onClose 方法会在对话框关闭时更新 dialog$,并向订阅者(特别是 app)发出更新。

Vue.component('mydialog', 
  props:
    dialog: 
      type: Boolean,
      default: false
    
  ,

  template: `
<div class="text-xs-center">
    <v-dialog
      v-model="dialog$"
      
    >

      <v-card>
        <v-card-title
          class="headline grey lighten-2"
          primary-title
        >
          A Dialog
        </v-card-title>

        <v-card-text>
          Lorem ipsum dolor sit amet,
        </v-card-text>

        <v-divider></v-divider>

        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn
            color="primary"
            flat
            @click="onClose"
          >
            Close
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>
`,
  data: function() 
    return 
      dialog$: false,
    ;
  ,
  methods: 
    onClose() 
      this.dialog$ = false;
      this.$emit('update:dialog', this.dialog$);
    ,
  ,
  watch: 
    dialog: 
      immediate: true,
      handler() 
        this.dialog$ = this.dialog;
      ,
    ,
  
);

new Vue(
  el: '#app',
  data: 
    dialog: false
  ,
  template: `
    <v-app id="inspire">
      <v-btn color="red lighten-2" dark @click="dialog=true">Click Me</v-btn>
      <mydialog :dialog.sync="dialog"></mydialog>
    </v-app>
  `,

);
<!doctype html>
<html>

<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.css" />
</head>

<body>
  <div id="app"></div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.js"></script>
</body>

</html>

正如@raina77ow 所提到的,您也可以使用event bus 解决此类问题,但在这种情况下没有必要。

【讨论】:

以上是关于重构vue单文件组件的主要内容,如果未能解决你的问题,请参考以下文章

Vue 单文件组件 (SFC) 规范

vue单文件组件实例1:简单单文件组件

Vue 学习总结笔记

vue单文件组件实例2:简单单文件组件

灵活使用vue单文件组件之--最少配置打包.vue组件

vue单文件组件怎么引入swiper.js?