发布于2021-01-31 14:11 阅读(1686) 评论(0) 点赞(23) 收藏(4)
Vue.component('my-component-name', {
// ... 选项 ...
})
我们可以用这种方式来创建全局组件,在实例化Vue之前用Vue.component
来创建组件,这样我们可以在任何实例化Vue的组件(new Vue
)中使用。
可能会报错:
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
处理方法:在项目vue.config.js
中,修改runtimeCompiler
为true
我们可以以普通对象的方式创建组件,对象中可以包含我们常用的data
、methods
等属性和方法,比如下面这样
var ComponentA = { /* ... */ }
注册局部组件的话。需要我们在要使用组件的地方(大多数情况下也是组件)使用components
来注册
Demo.vue
<template>
<div>Demo</div>
</template>
首先导入组件,然后使用components
注册组件,最后在template
中使用组件
<template>
<demo></demo>
</template>
<script>
import Demo from './Demo';
export default {
......
components: {
Demo,
}
}
</script>
<script type="text/x-template" id="xTemplate">
<div>content</div>
</script>
<script>
Vue.component('xTemplateDemo', {
template: '#xTemplate',
......
});
</script>
使用过像elementUI
和iview
之类的第三方组件库的同学可能都知道,他们提供了很多全局的API可以很方便的创建组件,比如弹出框等,他们是怎么做的呢,我们下面就来看看。
// components/Dialog/Dialog.vue
<template>
<transition name="fade">
<div class="dialog-page" @click.self="close" v-if="isShow">
<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,
default: '提示',
}
},
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>
.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 0.2s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
</style>
新建文件
// components/Dialog/index.js
import Vue from 'vue';
import Dialog from "@/components/Dialog/Dialog";
let vm;
function createVNode(resolve, reject, 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
没有传参数,会挂载到哪里呢?
其实是需要我们手动挂载的。当前组件在渲染完成后,手动把当前组件的DOM插入到body
中,在组件销毁前移除掉。
接着说我们的组件,这里我们又看到一个createVNode
方法,不用说,这个就是用来创建组件的方法了,可以看到它返回了一个Vue
的实例化对象(虚拟DOM),new Vue
的参数混入了一些生命周期函数,和两个methods
方法,以及上段所说挂载dom与销毁dom。
最重要的还是下面的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
提供的一些方法有点相似呢,没错,其实他们也是这么做的。
原文链接:https://blog.csdn.net/weixin_44116302/article/details/112795765
作者:前端大师
链接:http://www.qianduanheidong.com/blog/article/71/c45b3e4829cfed45a1ad/
来源:前端黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 前端黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-3
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!