Maison  >  Article  >  interface Web  >  méthode vuejs pour appeler des composants

méthode vuejs pour appeler des composants

藏色散人
藏色散人original
2021-11-01 11:16:583371parcourir

Comment appeler des composants dans vuejs : 1. Contrôler explicitement l'affichage et le masquage des composants via v-model ou .sync ; 2. Appeler via le code js 3. Appeler via les instructions Vue.

méthode vuejs pour appeler des composants

L'environnement d'exploitation de cet article : système Windows 7, vue version 2.9.6, ordinateur DELL G3.

Trois façons d'appeler les composants Vue

Récemment, j'ai rencontré quelques problèmes lors de l'écriture de fj-service-system. Autrement dit, pour certains de mes composants, tels que Dialog et Message, dois-je introduire des bibliothèques de composants tiers, telles que element-ui, ou dois-je en implémenter une moi-même ? Bien qu'ils aient pour fonction d'introduire à la demande, le style général ne correspond pas à l'ensemble de mon système. Vous pouvez donc envisager d’implémenter vous-même ces composants simples manuellement.

Habituellement, lorsque nous lisons des articles sur Vue, ce que nous pouvons voir parle généralement des pages de développement de composants Vue à fichier unique. Il existe relativement peu d’articles sur le développement d’un seul composant. Lorsque je travaillais sur le projet fj-service-system, j'ai trouvé que le développement d'un seul composant était également très intéressant. Vous pouvez l'écrire et l'enregistrer. Parce que ce que j'ai écrit n'est pas un framework d'interface utilisateur, c'est juste un enregistrement. Il n'y a pas de référentiel github, alors regardons le code.

  • v-model ou .sync contrôle explicitement l'affichage et le masquage des composants
  • Appelé via le code js
  • Appelé via les instructions Vue

Lors de l'écriture de composants, de nombreuses méthodes d'écriture et inspirations proviennent d'element-ui, merci.

Dialogue

J'ai l'habitude d'appeler cette chose une boîte de dialogue. En fait, on l'appelle aussi un composant modal (fenêtre contextuelle). En fait, une petite fenêtre apparaît sur la page, et le contenu de cette petite fenêtre peut être personnalisé. Il peut généralement être utilisé comme boîte de dialogue pour les fonctions de connexion.

Ce type de composant est très approprié pour contrôler explicitement l'apparition et la disparition via v-model ou .sync. Il peut être écrit directement sur la page puis contrôlé via des données - c'est aussi le composant le plus conforme aux idées de conception de Vue.

Pour cela, nous pouvons écrire un composant appelé Dialog.vue

<template>
  <div class="dialog">
    <div class="dialog__wrapper" v-if="visble" @clcik="closeModal">
      <div class="dialog">
        <div class="dialog__header">
          <div class="dialog__title">{{ title }}</div>
        </div>
        <div class="dialog__body">
          <slot></slot>
        </div>
        <div class="dialog__footer">
          <slot name="footer"></slot>
        </div>
      </div>
    </div>
    <div class="modal" v-show="visible"></div>
  </div></template><script>
  export default {    name: &#39;dialog&#39;,    props: {      title: String,      visible: {        type: Boolean,        default: false
      }
    },    methods: {      close() {        this.$emit(&#39;update:visible&#39;, false) // 传递关闭事件
      },      closeModal(e) {        if (this.visible) {          document.querySelector(&#39;.dialog&#39;).contains(e.target) ? &#39;&#39; : this.close(); // 判断点击的落点在不在dialog对话框内,如果在对话框外就调用this.close()方法关闭对话框
        }
      }
    }
  }</script>

Nous n'écrirons pas de CSS ou quoi que ce soit d'autre, cela n'a pas grand-chose à voir avec le composant lui-même. Cependant, il convient de noter que la classe dialog__wrapper ci-dessus est également en plein écran et transparente. Elle est principalement utilisée pour obtenir des événements de clic et verrouiller la position du clic. Elle utilise la méthode Node.contains() du DOM pour déterminer si le clic est effectué. position est la boîte de dialogue elle-même. Si Si vous cliquez en dehors de la boîte de dialogue, comme une couche modale translucide, un événement de fermeture sera envoyé pour fermer la boîte de dialogue.

Lorsque nous voulons l'appeler en externe, nous pouvons l'appeler comme suit :

<template>
  <div class="xxx">
    <dialog :visible.sync="visible"></dialog> 
    <button @click="openDialog"></button>
  </div></template><script>
  import Dialog from &#39;Dialog&#39;
  export default {    components: {
      Dialog
    },    data() {      return {        visible: false
      }
    },    methods: {      openDialog() {        this.visible = true // 通过data显式控制dialog
      }
    }
  }</script>

Afin de rendre l'ouverture et la fermeture de la boîte de dialogue plus attrayantes, vous pouvez essayer d'ajouter le composant 300ff3b250bc578ac201dd5fb34a00046087faffb1c3f26530d25a6b190c2f81 l'effet de transition, simplement. Une petite animation de transition serait également sympa.

Avis

Ce composant est similaire au message d'element-ui (invite de message). Ce qui m'attire le plus, c'est qu'il n'est pas appelé en écrivant explicitement la structure HTML du composant dans la page via v-model, mais en utilisant des méthodes telles que this.$message() dans js appelé. Bien que cette méthode va à l'encontre de la réflexion basée sur les données de Vue. Mais je dois dire que c'est vraiment pratique dans certaines situations.

Pour des composants tels que Notice, il vous suffit de demander quelques mots à la fois pour donner aux utilisateurs une simple invite de message. Les informations demandées peuvent être variées et des invites peuvent même être superposées. Si vous l'appelez via la première méthode, vous devez écrire la structure HTML à l'avance. C'est sans aucun doute une approche gênante et il est impossible de prédire combien de boîtes de message il y aura. Si vous l'appelez via la méthode js, il vous suffit de prendre en compte les différents textes et types appelés dans différentes situations.

L'approche précédente consistait à écrire un fichier Vue, puis à introduire la page via l'attribut composants et à écrire explicitement l'appel de balise. Alors comment appeler le composant via la méthode js ?

La clé ici est la méthode extend de Vue.

Le document ne donne pas de détails sur la façon dont extend peut être utilisé de cette manière. Il l'explique simplement comme un constructeur de composant Vue qui doit être monté manuellement.

En regardant le code source d'element-ui, nous pouvons comprendre comment implémenter les fonctions ci-dessus.

La première étape consiste à créer un fichier Notice.vue

<template>
  <div class="notice">
    <div class="content">
      {{ content }}    </div>
  </div></template><script>
  export default {    name: &#39;notice&#39;,
    data () {      return {        visible: false,        content: &#39;&#39;,        duration: 3000
      }
    },    methods: {      setTimer() {        setTimeout(() => {          this.close() // 3000ms之后调用关闭方法
        }, this.duration)
      },      close() {        this.visible = false
        setTimeout(() => {          this.$destroy(true)          this.$el.parentNode.removeChild(this.$el) // 从DOM里将这个组件移除
        }, 500)
      }
    },    mounted() {      this.setTimer() // 挂载的时候就开始计时,3000ms后消失
    }
  }</script>

Ce qui est écrit ci-dessus n'est pas très différent d'un composant Vue ordinaire à fichier unique. Mais la différence est qu'il n'y a pas d'accessoires, alors comment contrôler la visibilité de ce composant en externe ?

Un fichier js est donc nécessaire pour reprendre ce composant et appeler la méthode extend. Vous pouvez créer un fichier index.js dans le même répertoire.

import Vue from &#39;vue&#39;const NoticeConstructor = Vue.extend(require(&#39;./Notice.vue&#39;)) // 直接将Vue组件作为Vue.extend的参数let nId = 1const Notice = (content) => {  let id = &#39;notice-&#39; + nId++  const NoticeInstance = new NoticeConstructor({    data: {      content: content
    }
  }) // 实例化一个带有content内容的Notice

  NoticeInstance.id = id
  NoticeInstance.vm = NoticeInstance.$mount() // 挂载但是并未插入dom,是一个完整的Vue实例
  NoticeInstance.vm.visible = true
  NoticeInstance.dom = NoticeInstance.vm.$el  document.body.appendChild(NoticeInstance.dom) // 将dom插入body
  NoticeInstance.dom.style.zIndex = nId + 1001 // 后插入的Notice组件z-index加一,保证能盖在之前的上面
  return NoticeInstance.vm
}export default {  install: Vue => {
    Vue.prototype.$notice = Notice // 将Notice组件暴露出去,并挂载在Vue的prototype上
  }
}

Dans ce fichier, nous pouvons voir que grâce à NoticeConstructor, nous pouvons contrôler diverses propriétés d'un composant via js. Enfin, nous l'enregistrons dans le prototype Vue, afin de pouvoir utiliser la méthode this.$notice() à l'intérieur de la page, et nous pouvons facilement appeler ce composant pour écrire des effets de notification simples.

Bien sûr, n'oubliez pas que cela équivaut à un plug-in Vue, vous devez donc appeler la méthode Vue.use() dans le js principal :

// main.js

// ...
import Notice from 'notice/index.js'

Vue.use(Notice)

// ...

Loading

在看element-ui的时候,我也发现了一个很有意思的组件,是Loading,用于给一些需要加载数据等待的组件套上一层加载中的样式的。这个loading的调用方式,最方便的就是通过v-loading这个指令,通过赋值的true/false来控制Loading层的显隐。这样的调用方法当然也是很方便的。而且可以选择整个页面Loading或者某个组件Loading。这样的开发体验自然是很好的。

其实跟Notice的思路差不多,不过因为涉及到directive,所以在逻辑上会相对复杂一点。

平时如果不涉及Vue的directive的开发,可能是不会接触到modifiers、binding等概念。参考文档

简单说下,形如:v-loading.fullscreen="true"这句话,v-loading就是directive,fullscreen就是它的modifier,true就是binding的value值。所以,就是通过这样简单的一句话实现全屏的loading效果,并且当没有fullscreen修饰符的时候就是对拥有该指令的元素进行loading效果。组件通过binding的value值来控制loading的开启和关闭。(类似于v-model的效果)

其实loading也是一个实际的DOM节点,只不过要把它做成一个方便的指令还不是特别容易。

首先我们需要写一下loading的Vue组件。新建一个Loading.vue文件

<template>
  <transition
    name="loading"
  	@after-leave="handleAfterLeave">
    <div
      v-show="visible"
      class="loading-mask"
      :class={&#39;fullscreen&#39;: fullscreen}>
      <div class="loading">
        ...      </div>
      <div class="loading-text" v-if="text">
        {{ text }}      </div>
    </div>
  </transition></template><script>export default {  name: &#39;loading&#39;,
  data () {    return {      visible: true,      fullscreen: true,      text: null
    }
  },  methods: {    handleAfterLeave() {      this.$emit(&#39;after-leave&#39;);
    }
  }
}</script><style>.loading-mask{
  position: absolute; // 非全屏模式下,position是absolute
  z-index: 10000;
  background-color: rgba(255,235,215, .8);
  margin: 0;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  transition: opacity .3s;
}
.loading-mask.fullscreen{
  position: fixed; // 全屏模式下,position是fixed
}
// ...</style>

Loading关键是实现两个效果:

    1.全屏loading,此时可以通过插入body下,然后将Loading的position改为fixed,插入body实现。
    2.对所在的元素进行loading,此时需要对当前这个元素的的position修改:如果不是absolute的话,就将其修改为relatvie,并插入当前元素下。此时Loading的position就会相对于当前元素进行绝对定位了。
所以在当前目录下创建一个index.js的文件,用来声明我们的directive的逻辑。

import Vue from &#39;vue&#39;const LoadingConstructor = Vue.extend(require(&#39;./Loading.vue&#39;))export default {  install: Vue => {
    Vue.directive(&#39;loading&#39;, { // 指令的关键
      bind: (el, binding) => {        const loading = new LoadingConstructor({ // 实例化一个loading
          el: document.createElement(&#39;div&#39;),          data: {            text: el.getAttribute(&#39;loading-text&#39;), // 通过loading-text属性获取loading的文字
            fullscreen: !!binding.modifiers.fullscreen 
          }
        })
        el.instance = loading; // el.instance是个Vue实例
        el.loading = loading.$el; // el.loading的DOM元素是loading.$el
        el.loadingStyle = {};
        toggleLoading(el, binding);
      },      update: (el, binding) => {
        el.instance.setText(el.getAttribute(&#39;loading-text&#39;))        if(binding.oldValue !== binding.value) {
          toggleLoading(el, binding)
        }   
      },      unbind: (el, binding) => { // 解绑
        if(el.domInserted) {          if(binding.modifiers.fullscreen) {              document.body.removeChild(el.loading);
          }else {
            el.loading &&
            el.loading.parentNode &&
            el.loading.parentNode.removeChild(el.loading);
          }
        }
      }
    })    const toggleLoading = (el, binding) => { // 用于控制Loading的出现与消失
      if(binding.value) { 
        Vue.nextTick(() => {          if (binding.modifiers.fullscreen) { // 如果是全屏
            el.originalPosition = document.body.style.position;
            el.originalOverflow = document.body.style.overflow;
            insertDom(document.body, el, binding); // 插入dom
          } else {
            el.originalPosition = el.style.position;
            insertDom(el, el, binding); // 如果非全屏,插入元素自身
          }
        })
      } else {        if (el.domVisible) {
          el.instance.$on(&#39;after-leave&#39;, () => {
            el.domVisible = false;            if (binding.modifiers.fullscreen && el.originalOverflow !== &#39;hidden&#39;) {              document.body.style.overflow = el.originalOverflow;
            }            if (binding.modifiers.fullscreen) {              document.body.style.position = el.originalPosition;
            } else {
              el.style.position = el.originalPosition;
            }
          });
          el.instance.visible = false;
        }
      }
    }    const insertDom = (parent, el, binding) => { // 插入dom的逻辑
      if(!el.domVisible) {        Object.keys(el.loadingStyle).forEach(property => {
          el.loading.style[property] = el.loadingStyle[property];
        });        if(el.originalPosition !== &#39;absolute&#39;) {
          parent.style.position = &#39;relative&#39;
        }        if (binding.modifiers.fullscreen) {
          parent.style.overflow = &#39;hidden&#39;
        }
        el.domVisible = true;
        parent.appendChild(el.loading) // 插入的是el.loading而不是el本身
        Vue.nextTick(() => {
          el.instance.visible = true;
        });
        el.domInserted = true;
      }
    }
  }
}

同样,写完整个逻辑,我们需要将其注册到项目里的Vue下:

// main.js

// ...
import Loading from 'loading/index.js'

Vue.use(Loading)

// ...

至此我们已经可以使用形如

adb2c97e42ba7ef7e89c2223cc327580

这样的方式来实现调用一个loading组件了。

总结

在用Vue写我们的项目的时候,不管是写页面还是写形如这样的功能型组件,其实都是一件很有意思的事情。本文介绍的三种调用组件的方式,也是根据实际情况出发而实际操作、实现的。不同的组件通过不同的方式去调用,方便了开发人员,也能更好地对代码进行维护。当然也许还有其他的方式,我并没有了解,也欢迎大家在评论里指出!

最后再次感谢element-ui的源码给予的极大启发。

推荐:《最新的5个vue.js视频教程精选

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn