关于前端:用这招监听-Vue-的插槽变化

46次阅读

共计 3951 个字符,预计需要花费 10 分钟才能阅读完成。

本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一工夫和你分享前端行业趋势,学习路径等等。
更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi,蕴含一线大厂面试残缺考点、材料以及我的系列文章。

快来收费体验 ChatGpt plus 版本的,咱们出的钱
体验地址:https://chat.waixingyun.cn/#/home
能够退出网站底部技术群,一起找 bug.

最近,每当组件的内容 (插槽、子组件等) 发生变化时,我须要更新它的状态。对于上下文,它是一个表单组件,用于跟踪其输出的有效性状态。

上面的代码片段是以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-…

代码部署后可能存在的 BUG 没法实时晓得,预先为了解决这些 BUG,花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。

交换

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

正文完
 0