重构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
组件侦听mydialog
的dialog
属性的更新。
在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单文件组件的主要内容,如果未能解决你的问题,请参考以下文章