首頁  >  文章  >  web前端  >  vuejs 呼叫元件的方法

vuejs 呼叫元件的方法

藏色散人
藏色散人原創
2021-11-01 11:16:583438瀏覽

vuejs呼叫元件的方法:1、透過v-model或.sync明確控制元件顯示隱藏;2、透過js程式碼呼叫;3、透過Vue指令呼叫。

vuejs 呼叫元件的方法

本文操作環境:windows7系統、vue2.9.6版,DELL G3電腦。

Vue元件的三種呼叫方式

最近在寫fj-service-system的時候,遇到了一些問題。那就是我有些元件,像是Dialog、Message這樣的元件,是引入三方元件庫,像是element-ui這樣的,還是自己實作一個?雖然它們有按需引入的功能,但是整體風格和我的整個系統不搭。於是就可以考慮自己手動實作這些簡單的元件了。

通常我們看Vue的一些文章的時候,我們能看到的通常是講Vue單一檔案元件化開發頁面的。單一組件開發的文章相對就較少了。我在做fj-service-system專案的時候,發現其實單一元件開發也是很有趣的。可以寫寫記錄下來。因為寫的不是什麼ui框架,所以也只是一個記錄,沒有github倉庫,權且看代碼吧。

  • v-model或.sync明確控制元件顯示隱藏
  • 透過js程式碼呼叫
  • 透過Vue指令呼叫

##在寫組件的時候很多寫法、靈感來自於element-ui,感謝。

Dialog

我習慣把這個東西叫做對話框,其實還有叫做modal(彈窗)元件的叫法。其實就是在頁面裡,彈出一個小窗口,這個小窗口裡的內容可以客製化。通常可以用來做登入功能的對話框。

這種元件就很適合透過v-model或.sync的方式來明確的控制出現和消失。它可以直接寫在頁面裡,然後透過data去控制──這也是最符合Vue的設計想法的元件。

###為此我們可以寫一個元件就叫做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>
###CSS什麼的就不寫了,跟元件本身關係比較小。不過值得注意的是,上面的dialog__wrapper這個class也是全螢幕的,透明的,主要用於獲取點擊事件並鎖定點擊的位置,透過DOM的Node.contains()方法來判斷點擊的位置是不是dialog本身,如果是點擊到了dialog外面,例如半透明的modal層那麼就派發關閉事件,把dialog給關閉掉。 ######當我們在外部要呼叫的時候,就可以如下呼叫:###
<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>
###為了Dialog開啟和關閉好點,你可試著加上300ff3b250bc578ac201dd5fb34a00046087faffb1c3f26530d25a6b190c2f81組件配合上過渡效果,簡單的一點過渡動效也會很好看。 ######Notice######這個元件類似element-ui的message(訊息提示)。它吸引我的最大的地方在於,它不是透過顯式的在頁面裡寫好元件的html結構透過v-model去呼叫的,而是透過在js裡透過形如this.$message()這樣的方法調用的。這種方法雖然跟Vue的數據驅動的思想有所違背。不過不得不說在某些情況下真的特別方便。 ###############對於Notice這種元件,一次只要提示幾個文字,給使用者簡單的訊息提示就行了。提示的資訊可能是多變的,甚至可以出現疊加的提示。如果透過第一種方式去調用,事先就得寫好html結構,這無疑是麻煩的做法,而且無法預知有多少訊息提示框。而透過js的方法呼叫的話,只需要考慮不同情況呼叫的文字、型別不同就可以了。 ######而之前的做法都是寫一個Vue文件,然後透過components屬性引入頁面,明確寫入標籤調用的。那麼如何將元件通過js的方法去呼叫呢? ######這裡的關鍵是Vue的extend方法。 ######文件裡並沒有詳細給出extend能這麼用,只是作為需要手動mount的一個Vue的組件構造器說明了一下而已。 ######透過查看element-ui的源碼,才算是理解如何實現上述的功能。 ######首先仍然是建立一個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>
###上面寫的東西跟普通的一個單一檔案Vue元件沒有太大的差別。不過差別就在於,沒有props了,那麼是如何透過外部來控制這個元件的顯隱呢? ######所以還需要一個js檔案來接管這個元件,並呼叫extend方法。同目錄下可以建立一個index.js的檔案。 ###
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上
  }
}
###這個檔案裡我們能看到透過NoticeConstructor我們能夠透過js的方式去控制一個元件的各種屬性。最後我們把它註冊進Vue的prototype上,這樣我們就可以在頁面內部使用形如this.$notice()方法了,可以方便調用這個元件來寫做出簡單的通知提示效果了。 ######當然別忘了這個相當於一個Vue的插件,所以需要去主js裡呼叫一下Vue.use()方法:###
// 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视频教程精选

以上是vuejs 呼叫元件的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn