前言
当初前端开发中应用Vue的预计比拟多,组件也是Vue比拟外围的内容,也是咱们平时开发中接触最多的货色了,那么什么是组件呢?组件能够是小到一个按钮,一个图标,也能够大到一个页面,甚至是一个零碎。
最近接手了一个Vue的我的项目,能够说是学到了不少货色,当然也包含本篇说的“组件”,所以想着写下来分享一下。这篇文章不讲组件的根底,只讲创立组件(注册)的几种形式。
全局注册
Vue.component('my-component-name', { // ... 选项 ...})
咱们能够用这种形式来创立全局组件,在实例化Vue之前用Vue.component
来创立组件,这样咱们能够在任何实例化Vue的组件(new Vue
)中应用。
具体形式
1、注册组件
Vue.component('component-a', { /* ... */ })Vue.component('component-b', { /* ... */ })Vue.component('component-c', { /* ... */ })new Vue({ el: '#app' })
2、应用组件
<div id="app"> <component-a></component-a> <component-b></component-b> <component-c></component-c></div>
这样咱们就胜利创立注册并应用了组件,并且咱们还能够在所创立的组件外部互相应用。
部分注册
咱们能够以一般对象的形式创立组件,对象中能够蕴含咱们罕用的data
、methods
等属性和办法,比方上面这样
var ComponentA = { /* ... */ }var ComponentB = { /* ... */ }var ComponentC = { /* ... */ }
注册部分组件的话。须要咱们在要应用组件的中央(大多数状况下也是组件)应用components
来注册,具体代码如下
new Vue({ el: '#app', components: { 'component-a': ComponentA, 'component-b': ComponentB }})
单文件组件
可能更多时候咱们是应用webpack
来构建咱们的我的项目(比方:vue-cli
),写的更多的是单文件组件,须要在组件中应用另一个组件,上面我就写一下
咱们就在vue-cli3
的根底上写,首先咱们像下面那种形式一样创立一个组件
// /components/Dialog/Dialog.vue<template> <transition name="fade" v-if="isShow"> <div class="dialog-page"> <div class="dialog-box"> <h3 class="title">{{ title }}</h3> <span class="close">X</span> <el-button type="primary" class="confirm-btn">确定</el-button> </div> </div> </transition></template><script>export default { name: "Dialog", props: { title: { type: String } }, data() { return { isShow: false } }, mounted() { this.isShow = true; }}</script><style lang="scss" scoped>.dialog-page { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 0.6); z-index: 99999; .dialog-box { position: absolute; top: 20%; left: 50%; transform: translateX(-50%); margin: auto; width: 700px; height: 400px; padding-top: 20px; background-color: #fff; border-radius: 10px; box-shadow: 0 0 6px 0 #fff; .title { text-align: center; font-size: 22px; color: #333; } .close { position: absolute; right: 20px; top: 20px; cursor: pointer; } .confirm-btn { width: 80%; position: absolute; left: 10%; bottom: 50px; } }}.fade-enter-active, .fade-leave-active { transition: opacity .2s;}.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0;}</style>
而后在App.vue中应用
// App.vue<template> <div id="app"> <Dialog title="自定义弹窗组件" /> </div></template><script>import Dialog from "components/Dialog/Dialog";export default { name: 'app', components: { Dialog, }}</script>
这个时候如果运行我的项目,页面是这个样子(确认按钮我应用了elementUI哦)
首先导入组件,而后应用components
注册组件,最初在template
中应用组件,这样咱们就胜利实现了一个组件的创立和应用。这种形式是我迄今为止应用最多的形式,当然也可能满足大部分的需要了。
然而有的状况下这种事不够用的,比方一些用于告诉的弹框或者交互的组件,这种组件平时是不显示的,只有触发了某些动作的时候才会显示,如果咱们还应用这种形式的话,就要先引入组件,而后再注册,最初在页面中应用,并且咱们还要管制组件的显示与否,是不是减少很多无用的变量和代码,那么咱们能不能用更简略不便的形式来创立组件呢?答案必定是有的,往下看。
办法调用式创立
应用过像elementUI
和iview
之类的第三方组件库的同学可能都晓得,他们提供了很多全局的API能够很不便的创立组件,比方弹出框等,他们是怎么做的呢,咱们上面就来看看。还是接着下面的弹框组件写。
首先略微改变一下方才写的组件,加一些事件(敞开和确认)进去
// /components/Dialog/Dialog.vue<template> <transition name="fade" v-if="isShow"> <div class="dialog-page"> <div class="dialog-box"> <h3 class="title">{{ title }}</h3> <span class="close" @click="close">X</span> <el-button type="primary" class="confirm-btn" @click="confirm">确定</el-button> </div> </div> </transition></template><script>export default { name: "Dialog", props: { title: { type: String } }, data() { return { isShow: false } }, mounted() { window.addEventListener('keyup', this.close) this.isShow = true; }, methods: { close() { this.isShow = false; // 这里应用$nextTick是因为咱们应用了过渡成果,敞开的时候先过渡,再销毁 this.$nextTick(() => { this.$emit('close') }) }, confirm() { this.$emit('confirm') } }}</script><style lang="scss" scoped>/* 和下面一样,太长不写了 */...</style>
新建文件
// /components/Dialog/index.jsimport Vue from 'vue';import Dialog from "@/components/Dialog/Dialog";let vm;const noop = () => {};function createVNode(resolve = noop, reject = noop, props) { return new Vue({ mixins: [{ mounted() { document.body.appendChild(this.$el); }, beforeDestroy() { document.body.removeChild(this.$el); }, }], beforeDestroy() { vm = null; }, methods: { confirm() { resolve('点击确认'); this.$destroy(); }, close() { reject('点击敞开'); this.$destroy(); } }, render(createElement) { return createElement(Dialog, { on: { confirm: this.confirm, close: this.close }, props, style: { color: 'red' }, }); } })}function show(props) { return new Promise((resolve, reject) => { // 如果有vm这个实例,先销毁 if (vm) { vm.$destroy(); } vm = createVNode(resolve, reject, props); vm.$mount(); })}export default show;
倒着看,咱们导出了一个show
办法,它返回的是一个Promise
,这就是说咱们在调用这个办法的时候能够用.then
的语法在将来某一个时刻(敞开弹框,或者点击确认)执行一些操作。
接着咱们创立了一个vm实例,调用了$mount
,是不是看着比拟相熟,没错,在main.js
文件中
// main.js...new Vue({ ... render: h => h(App),}).$mount('#app');
它把new vue
的生成的虚构DOM转换成实在DOM挂载到了#app
下面,那下面咱们的$mount
没有传参数,会挂载到哪里呢?其实是须要咱们手动挂载的,这个就给个传送门吧。
接着说咱们的组件,这里咱们又看到一个createVNode
办法,不用说,这个就是用来创立组件的办法了,能够看到它返回了一个Vue
的实例化对象(虚构DOM),new Vue
的参数混入了一些生命周期函数,和两个methods
办法,其中在组件渲染实现后手动把以后组建的DOM插入到body
中,在组件销毁前移除掉。
最重要的还是上面的render
函数,这个内容很多,就不开展说了(我本人也是只知其一;不知其二,说不好????),想深刻理解能够单击传送门,能够简略了解render
能够生成VNode
,就是虚构节点。它的第一个参数是方才咱们编写的组件,第二个参数是一个对象,能够定义一些参数,比方要传给组件的参数、款式还有监听的事件等。
这样咱们new Vue
的时候,没有用template
的形式,而是用了render
函数来生成咱们要的组件,手动挂载到DOM中去(不在#app
外面,是并列的关系,都在body
上面)。
接下来咱们就能够在须要的中央调用了,比方App.vue
// App.vue<template> <div id="app"> <button @click="handleClick">Dialog</button> </div></template><script>import Dialog from '@/components/Dialog/index'export default { name: 'app', methods: { handleClick() { Dialog({ title: '测试弹框' }).then(res => { console.log(res) }).catch(err => { console.log(err) }) } }}</script>
点击按钮的时候,咱们调用导入的Dialog
办法,传了title
参数,当初咱们能够看看成果
到当初咱们曾经实现了组件的创立和调用,而且咱们点击敞开
和确认
的时候能够看看控制台,是不是别离打印了
这就是咱们在App.vue
外面调用Dialog
办法的时候别离在then
和catch
外面打印的,回到下面/components/Dialog/index.js
文件中的show
办法,咱们返回的是promise
,而且咱们把resolve
和reject
两个参数传入了createVNode
办法中,别离在methods
中的两个对应确认和敞开的办法中别调用,那么confirm
和close
是怎么被触发的呢
能够看/components/Dialog/Dialog.vue
文件中,咱们在点击的时候,应用了$emit
来触发对应的事件,那么事件是在哪里被接管的呢?回到/components/Dialog/index.js
文件中的render
函数,咱们在createElement
办法的第二个参数中有一个on
对象,是不是感觉很相熟,没错,就是用来监听事件的,咱们下面用$emit
触发的事件也是在这里监听的。这样咱们就在点击确认
或者敞开
后,执行resolve
或者reject
办法,而后就能够在then
和catch
中执行相应的操作了。
注册全局插件
到下面为止,咱们曾经能够很不便的以API的模式来创立组件,然而可能有人会感觉还不够不便,每次还要先导入,再调用,有没有更不便的形式呢?必定是有的,当初咱们就来试试。
其实也很简略,只须要把方才的代码略微改一下就能够了
// /component/Dialog/index.js...- export default show;+ export default {+ install(vue) {+ vue.prototype.$Dialog = show;+ }+ }
// main.js+ import Dialog from '@/components/Dialog/index'+ Vue.use(Dialog);
看到Vue.use
又有了相熟的感觉吧,咱们平时应用插件不就是这么用的嘛!没错,第三方的插件可能以Vue.use
的形式注册,是因为他们都在插件外面导出了一个install
办法,不分明的看这里哦 Vue.use。
这样咱们就能够在须要的中央应用this.$Dialog
调用了,也不须要先导入了,因为办法曾经被挂到了Vue
的原型上。
当初就来试一下
// App.vue<template> <div id="app"> <button @click="handleClick">Dialog</button> </div></template><script>export default { name: 'app', methods: { handleClick() { this.$Dialog({ title: '测试弹框' }).then(res => { console.log(res) }).catch(err => { console.log(err) }) } }}</script>
成果和方才是一样的,就不贴图了。ok,到这里是不是感觉和ElementUI
提供的一些办法有点类似呢,没错,其实他们也是这么做的。
结语
本文次要介绍了几种创立组件的形式,具体要用哪一种还看依据具体的业务场景来抉择,正所谓没有最好的技术计划,只有最合适的。然而说归说,多把握一点总是好的,前面的内容就波及到Vue
中比拟难把握的内容,比方render
、createElement
、$mount
等。其实这些货色更靠近底层,通过学习这些咱们能够更粗浅的了解Vue
,而不只是停留在“会用”的阶段。
好了,就先说到这里,喜爱或者感觉有用能够点赞 + 珍藏哦,有谬误之处也欢送指出!!!
刚封装了一个Vue图片预览的插件(vue-preview-imgs
)也是我封装的第一个插件,还有很多有余,欢送一起交换,喜爱给个star哦!地址:https://github.com/hzpeng57/v...