vuejs에서 구성요소를 호출하는 방법: 1. v-model 또는 .sync를 통해 구성요소의 표시 및 숨기기를 명시적으로 제어합니다. 2. js 코드를 통해 호출합니다. 3. Vue 지침을 통해 호출합니다.
이 기사의 운영 환경: Windows 7 시스템, vue 버전 2.9.6, DELL G3 컴퓨터.
Vue 구성 요소를 호출하는 세 가지 방법
최근 fj-service-system을 작성할 때 몇 가지 문제에 직면했습니다. 즉, Dialog 및 Message와 같은 일부 구성 요소에 대해 element-ui와 같은 타사 구성 요소 라이브러리를 도입해야 합니까, 아니면 직접 구현해야 합니까? 온디맨드 방식으로 도입하는 기능이 있지만 전반적인 스타일이 내 전체 시스템과 일치하지 않습니다. 따라서 이러한 간단한 구성 요소를 직접 수동으로 구현하는 것을 고려할 수 있습니다.
보통 Vue에 관한 기사를 읽을 때 우리가 볼 수 있는 것은 Vue 단일 파일 구성 요소 개발 페이지에 대한 이야기입니다. 단일 구성 요소 개발에 관한 기사는 상대적으로 적습니다. fj-service-system 프로젝트를 진행하면서 단일 컴포넌트 개발도 매우 흥미롭다는 것을 알았습니다. 적어서 녹음하시면 됩니다. 제가 작성한 것은 UI 프레임워크가 아니기 때문에 그냥 기록일 뿐입니다. github 저장소가 없으므로 코드를 살펴보겠습니다.
컴포넌트를 작성할 때 element-ui에서 많은 작성 방법과 영감을 얻습니다. 감사합니다.
저는 이것을 대화 상자라고 부르는 데 익숙합니다. 사실 모달(팝업 창) 구성 요소라고도 합니다. 실제로 페이지에 작은 창이 나타나고 이 작은 창의 내용을 사용자 정의할 수 있습니다. 일반적으로 로그인 기능을 위한 대화 상자로 사용할 수 있습니다.
이런 종류의 컴포넌트는 v-model이나 .sync를 통해 나타나거나 사라지는 것을 명시적으로 제어하는 데 매우 적합합니다. 페이지에 직접 작성한 다음 데이터를 통해 제어할 수 있습니다. 이는 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: 'dialog', props: { title: String, visible: { type: Boolean, default: false } }, methods: { close() { this.$emit('update:visible', false) // 传递关闭事件 }, closeModal(e) { if (this.visible) { document.querySelector('.dialog').contains(e.target) ? '' : this.close(); // 判断点击的落点在不在dialog对话框内,如果在对话框外就调用this.close()方法关闭对话框 } } } }</script>
CSS나 다른 어떤 것도 작성하지 않을 것이며 구성 요소 자체와는 거의 관련이 없습니다. 그러나 위의Dialog__wrapper 클래스도 전체 화면이고 투명하다는 점은 주목할 가치가 있습니다. 이는 주로 클릭 이벤트를 획득하고 클릭 위치를 잠그는 데 사용됩니다. 이는 클릭 여부를 결정하기 위해 DOM의 Node.contains() 메서드를 사용합니다. position은 대화 상자 자체입니다. 반투명 모달 레이어와 같은 대화 상자 외부를 클릭하면 닫기 이벤트가 전달되어 대화 상자를 닫습니다.
외부적으로 호출하려면 다음과 같이 호출하면 됩니다.
<template> <div class="xxx"> <dialog :visible.sync="visible"></dialog> <button @click="openDialog"></button> </div></template><script> import Dialog from 'Dialog' export default { components: { Dialog }, data() { return { visible: false } }, methods: { openDialog() { this.visible = true // 通过data显式控制dialog } } }</script>
대화상자 열기 및 닫기를 더욱 매력적으로 만들기 위해 일치하는 300ff3b250bc578ac201dd5fb34a00046087faffb1c3f26530d25a6b190c2f81 구성 요소를 추가해 볼 수 있습니다. 전환 효과, 간단히 말해서 약간의 전환 애니메이션도 멋져 보일 것입니다.
element-ui의 메시지(메시지 프롬프트)와 유사한 컴포넌트입니다. 가장 끌리는 점은 v-model을 통해 페이지에 있는 컴포넌트의 HTML 구조를 명시적으로 작성하여 호출하는 것이 아니라, js에서 this.$message()와 같은 메소드를 사용하여 호출한다는 점입니다. 이 방법은 Vue의 데이터 중심 사고에 어긋납니다. 하지만 어떤 상황에서는 정말 편리하다고 말씀드리고 싶습니다.
Notice와 같은 구성 요소의 경우 사용자에게 간단한 메시지 프롬프트를 제공하려면 한 번에 몇 단어만 프롬프트하면 됩니다. 프롬프트되는 정보는 다양할 수 있으며 겹쳐진 프롬프트가 있을 수도 있습니다. 첫 번째 방법을 통해 호출한다면 미리 html 구조를 작성해야 하는데 이는 분명 번거로운 접근 방법이고, 메시지 상자가 얼마나 될지 예측하는 것도 불가능하다. js 메소드를 통해 호출한다면, 다양한 상황에서 호출되는 텍스트와 타입만 고려하면 됩니다.
이전 접근 방식은 Vue 파일을 작성한 다음 구성 요소 속성을 통해 페이지를 소개하고 태그 호출을 명시적으로 작성하는 것이었습니다. 그렇다면 js 메서드를 통해 구성 요소를 호출하는 방법은 무엇입니까?
여기서 핵심은 Vue의 확장 방법입니다.
문서에서는 확장을 어떻게 이런 식으로 사용할 수 있는지에 대한 자세한 내용을 제공하지 않습니다. 단지 수동으로 마운트해야 하는 Vue 구성 요소 생성자로 설명합니다.
element-ui의 소스코드를 보면 위의 기능을 어떻게 구현하는지 이해할 수 있습니다.
첫 번째 단계는 NOTICE.vue 파일을 만드는 것입니다
<template> <div class="notice"> <div class="content"> {{ content }} </div> </div></template><script> export default { name: 'notice', data () { return { visible: false, content: '', 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 파일이 필요합니다. 동일한 디렉터리에 index.js 파일을 만들 수 있습니다.
import Vue from 'vue'const NoticeConstructor = Vue.extend(require('./Notice.vue')) // 直接将Vue组件作为Vue.extend的参数let nId = 1const Notice = (content) => { let id = 'notice-' + 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上 } }
이 파일에서 우리는 통지Constructor를 통해 js를 통해 컴포넌트의 다양한 속성을 제어할 수 있다는 것을 알 수 있습니다. 마지막으로 Vue 프로토타입에 등록하여 페이지 내에서 this.$notice() 메서드를 사용할 수 있고, 이 컴포넌트를 쉽게 호출하여 간단한 알림 효과를 작성할 수 있습니다.
물론, 이는 Vue 플러그인과 동일하므로 기본 js에서 Vue.use() 메서드를 호출해야 한다는 점을 잊지 마세요.
// main.js // ... import Notice from 'notice/index.js' Vue.use(Notice) // ...
在看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={'fullscreen': fullscreen}> <div class="loading"> ... </div> <div class="loading-text" v-if="text"> {{ text }} </div> </div> </transition></template><script>export default { name: 'loading', data () { return { visible: true, fullscreen: true, text: null } }, methods: { handleAfterLeave() { this.$emit('after-leave'); } } }</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 'vue'const LoadingConstructor = Vue.extend(require('./Loading.vue'))export default { install: Vue => { Vue.directive('loading', { // 指令的关键 bind: (el, binding) => { const loading = new LoadingConstructor({ // 实例化一个loading el: document.createElement('div'), data: { text: el.getAttribute('loading-text'), // 通过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('loading-text')) 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('after-leave', () => { el.domVisible = false; if (binding.modifiers.fullscreen && el.originalOverflow !== 'hidden') { 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 !== 'absolute') { parent.style.position = 'relative' } if (binding.modifiers.fullscreen) { parent.style.overflow = 'hidden' } 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!