最近,每当组件的内容(插槽、子组件等)发生变化时,我需要更新它的状态。对于上下文,它是一个表单组件,用于跟踪其输入的有效性状态。
下面的代码片段是以Options api格式编写的,但除了指定的地方外可以在vue2 和 Vue2中使用。
先从控制表单状态开始,根据状态修改一个类,孩子内容使用<slot/>填充:
<template>
<form :class="{ '--invalid': isInvalid }">
<slot />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
};
</script>
为了更新isInvalid属性,我们需要添加一个触发的事件,可以使用 sumit 事件 ,但我更喜用 input 事件。
表单事件7个: focus, blur, input, select, change, reset, submit 等,具体详解看这篇文章:https://blog.csdn.net/qq_43797996/article/details/103066452
表单不会触发 input 事件,但我们可以使用 "事件委托"。我们将监听器附加到父元素(<form>)上,当事件发生在它的子元素(<input>、<select>、<textarea>等)上时就会被触发。
任何时候在这个组件的<slot>中触发input事件,表单将捕获该事件。
<template>
<form :class="{ '--invalid': isInvalid }" @input="validate">
<slot />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
methods: {
validate() {
// 验证逻辑
}
}
};
</script>
验证逻辑可以是简单或复杂的。本文为了演示,用简单的方法,使用form.checkValidity() API 来查看表单是否基于html验证属性而有效。
为了访问<form>元素。可以用refs或$el属性。为了简单起见,本文使用$el。
<template>
<form :class="{ '--invalid': isInvalid }" @input="validate">
<slot />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
methods: {
validate() {
this.isInvalid = !this.$el.checkValidity()
}
}
};
</script>
这里有一点问题。如果表单的内容改变了,会发生什么?如果一个<input>在表单加载被添加到dom中,会发生什么?
举个例子,我们把这个表单组件称为 "MyForm",在 App 中,内容如下:
// App.vue
<template>
<MyForm>
<input
v-model="showInput"
id="toggle-name"
name="toggle-name"
type="checkbox"
/>
<label for="toggle-name">显示其它 input</label>
<template v-if="showInput">
<label for="name">Name:</label>
<input id="name" name="name" required />
</template>
<button type="submit">提交</button>
</MyForm>
</template>
<script>
import Form from "./components/form.vue";
export default {
name: "App",
components: {
MyForm: Form,
},
data: () => ({
showInput: false,
}),
};
</script>
当App.vue通过条件来隐藏显示某些 input,我们的表单需要知道。在这种情况下,我们会想到在表单内容发生变化时跟踪其有效性,而不仅仅是在 input 事件或mounted生命周期钩子上。否则,可能会显示不正确的信息。
熟悉 Vue的生命周期钩子小伙伴,这里可能会想到使用 update 来跟踪变化。理论上,这听起来不错。在实践中,它会创造一个无限的循环,然后浏览器挂了。
经过一番研究和测试,最佳解决方案是使用MutationObserver API。它是浏览器内置的方法,提供了监视对DOM树所做更改的能力,如果节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。
它是原生的方法,所以不受限于框架。
使用时,首先使用MutationObserver构造函数,新建一个观察器实例,同时指定这个实例的回调函数。在每次 DOM 变动后调用,这个回调都被调用。该回调函数接受两个参数,第一个是变动数组,第二个是观察器实例,将我们的 form 组件改写成如下:
<template>
<form :class="{ '--invalid': isInvalid }" @input="validate">
<slot />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
mounted() {
const observer = new MutationObserver(this.validate);
observer.observe(this.$el, {
childList: true,
subtree: true,
});
this.observer = observer;
},
methods: {
validate() {
this.isInvalid = !this.$el.checkValidity();
},
},
beforeUnmount() {
this.observer.disconnect();
},
};
</script>
<style scoped>
</style>
这里还需要使用 beforeUnmount生命周期事件来断开observer的连接,这会清除它所分配的任何内存。
最后,我们将isInvalid状态传递给要访问的内容的插件槽,这也称作用域的槽,它非常有用。
<template>
<form :class="{ '--invalid': isInvalid }" @input="validate">
<slot v-bind="{ isInvalid }" />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
mounted() {
const observer = new MutationObserver(this.validate);
observer.observe(this.$el, {
childList: true,
subtree: true,
});
this.observer = observer;
},
methods: {
validate() {
this.isInvalid = !this.$el.checkValidity();
},
},
beforeUnmount() {
this.observer.disconnect();
},
};
</script>
通过这样的设置,可以在我们的表单组件中添加任意数量的 input,并添加任何它需要的条件渲染逻辑。只要input使用HTML验证属性,表单就会跟踪它是否处于有效状态。
此外,由于使用的是作用域槽,我们将表单的状态提供给父级,所以父级可以对有效性的变化做出反应。
例如,在 App.vue,我们想在表单无效时 "禁用" 提交按钮,可以这么来写
<template>
<MyForm>
<template slot:default="form">
<label for="name">Name:</label>
<input id="name" name="name" required>
<button
type="submit"
:class="{ disabled: form.isInvalid }"
>
Submit
</button>
</template>
</MyForm>
</template>
nice~.
希望本文能对你未来的开必有所帮助。
作者:Dmitri Pavlutin 译者:前端小智 来源:Dmitri Pavlutin
原文:https://austingil.com/watching-changes-vue-js-component-slot-content/
本文针对 Vue 中如何控制组件子树之外的东西,探讨了四种解决方案,并展示了每种解决方案的优缺点。希望读者能从中受到启发。问你个问题,以前你可能从来没想过:有没有办法从子组件填充父组件插槽?
插槽我对他的理解就是父组件的东西插到子组件的<slot></slot>里面,也不知道这样理解对不对,方便自己记忆;作用域插槽我对他的理解就是数据在子组件里面,父组件可以用
作用域插槽是 Vue.js 中一个很有用的特性,可以显著提高组件的通用性和可复用性。问题在于,它实在不太好理解。尝试搞清楚父子作用域之间错综复杂的关系,其痛苦程度不亚于求解一个棘手的数学方程。
在本文中我们讨论 Vue 中的无渲染插槽模式能够帮助解决哪些问题。在 Vue.js 2.3.0 中引入的作用域插槽显著提高了组件的可重用性。无渲染组件模式应运而生,解决了提供可重用行为和可插入表示的问题。
有时让插槽内容能够访问子组件中才有的数据是很有用的。但是由于子组件的作用域在子组件,而父组件的作用域在父组件,这样一来,父组件就访问不到子组件的信息了,但是我们又不想用$emit发送事件去传递信息
作用域槽是Vue.js的一个有用特性,它可以使组件更加通用和可重用。唯一的问题是它们很难理解!试着让你的头在父母和孩子的范围内交织,就像解决一个棘手的数学方程。
注意v-slot只能添加在<template>上(只有一种例外情况),这一点和已经废弃的slotattribute不同。有时让插槽内容能够访问子组件中才有的数据是很有用的。例如,设想一个带有如下模板的<current-user>组件:
这篇文章将向您介绍如何使用Vue插槽在Vue.js中将数据从父组件传递到子组件。这篇文章适合所有阶段的开发人员(包括初学者)。
最近我弄清楚了如何递归地实现嵌套插槽,包括如何使用作用域插槽来实现。起因是我想看看是否可以构建一个复制v-for指令但仅使用template组件。
我们知道使用作用域插槽可以将数据传递到插槽中,但是如何从插槽传回来呢?将一个方法传递到我们的插槽中,然后在插槽中调用该方法。 我信无法发出事件
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!