# Vue组件之全局组件与局部组件
组件是 Vue 最强大的功能,可以扩展 HTML 元素,封装重用的代码。在较高层面,组件是自定义元素,Vue的编译器为它添加特殊功能。
- 全局组件,只要定义了,处处可以使用,性能不高,但是使用起来简单,名字建议 小写字母单词,中间用横线间隔
- 局部组件,定义了,要注册之后才能使用,性能比较高,使用起来有些麻烦,建议大些字母开头,驼峰命名
# 全局组件注册方式
Vue.component(组件名,{方法})
// 组件定义
Vue.component('comp', {
template: '<div>this is a component</div>'
})
vue版本如果有编译器环境才能使用模板template,而vuecli的webpack打包环境默认没有编译环境,只能用render函数来写
项目中的.vue文件,通过vue-loader会编译template为render函数,最终导出的依然是组件配置对象。
<body>
<div id="app">
<my-component></my-component>
</div>
<script>
Vue.component("my-component",{
template:"<h1>我是全局组件</h1>"
});
new Vue({
el:"#app"
});
</script>
</body>
在vuecli中可以使用jsx语法实现
components:{
"miss":{
render(){
return(
<div>2212321213122</div>
)
},
mounted(){
console.log("zzh")
}
}
},
- 全局组件必须写在Vue实例创建之前,才在该根元素下面生效;
<body>
<div id="app">
<my-component></my-component>
</div>
<div id="app1">
<my-component></my-component>
</div>
<script>
new Vue({
el: "#app"
});
Vue.component("my-component", {
template: "<h1>我是全局组件</h1>"
});
new Vue({
el: "#app1"
})
</script>
</body>
这样只会渲染app1根元素下面的,并不会渲染app根元素下面的,并且会报错。
- 模板里面第一级只能有一个标签,不能并行;
<body>
<div id="app">
<my-component></my-component>
</div>
<script>
new Vue({
el: "#app"
});
Vue.component("my-component", {
template: "<h1>我是全局组件</h1>" +
"<p>我是全局组件内标签</p>"
});
new Vue({
el: "#app1"
})
</script>
</body>
这样子会报错,并且只会渲染第一个标签h1;
# 局部组件注册方式
直接在Vue实例里面注册
<body>
<div id="app1">
<child-component></child-component>
</div>
<script>
new Vue({
el: "#app1",
components:{
"child-component":{
template:"<h1>我是局部组件</h1>"
}
}
});
</script>
局部组件需要注意:
1.属性名为 components ,s千万别忘了;
2.套路比较深,所以建议模板定义在一个全局变量里,代码看起来容易一点,如下
<body>
<div id="app1">
<child-component></child-component>
</div>
<script>
var child={
template:"<h1>我是局部组件</h1>"
};
new Vue({
el: "#app1",
components:{
"child-component":child
}
});
</script>
</body>
关于组件中的其他属性,可以和实例中的一样,但是data属性必须是一个函数:
<body>
<div id="app1">
<child-component></child-component>
</div>
<script>
var child={
template:"<button @click='add2'>我是局部组件:{{m2}}</button>",
data:function(){
return {m2:1}
},
methods:{
add2:function(){
this.m2++
}
}
};
new Vue({
el: "#app1",
components:{
"child-component":child
}
})
</script>
</body>
全局组件和局部组件一样,data也必须是一个函数:
<body>
<div id="app1">
<my-component></my-component>
</div>
<script>
Vue.component("my-component",{
template:"<button @click='add1'>全局组件:{{m1}}</button>",
data:function(){
return {
m1:10
}
},
methods:{
add1:function(){
this.m1++
}
}
});
new Vue({
el:"#app1"
})
</script>
</body>
当使用 DOM 作为模板时 (例如,将 el 选项挂载到一个已存在的元素上),你会受到 HTML 的一些限制,
因为 Vue 只有在浏览器解析和标准化 HTML 后才能获取模板内容。尤其像这些元素 <ul>,<ol>,
<table>,<select> 限制了能被它包裹的元素,而一些像<option>
这样的元素只能出现在某些其它元素内部。
自定义组件 <my-row> 被认为是无效的内容,因此在渲染的时候会导致错误。
变通的方案是使用特殊的 is 属性:
<body>
<div id="app1">
<ul>
<li is="my-component"></li>
</ul>
</div>
<script>
Vue.component("my-component",{
template:"<h1>{{message}}</h1>",
data:function(){
return {
message:"hello world"
}
}
});
new Vue({
el:"#app1"
})
</script>
</body>
对于全局与局部的作用域问题,我们可以这样理解,只要变量是在组件内部用的,这些变量必须是组件内部的,而在外部html结构中引用的变量,都引用的是该挂载下的实例里面的变量
<body>
<div id="app1">
<my-component></my-component>
</div>
<script>
Vue.component("my-component",{
template:"<button @click='add3'>" +
"{{message}}</button>",
data:function(){
return {
message:"hello world"
}
},
methods:{
add3:function(){
alert("我是局部")
}
}
});
new Vue({
el:"#app1",
methods:{
add3:function(){
alert("我是全局")
}
}
})
</script>
</body>
弹出框显示:我是局部
# 在vuecli中main写全局组件
Vue.component("comp",{
functional: true,//函数化,mounted失效,给render添加一个context上下文
//如果不加的话,则没有这个context,mounted有效
data(){
return{
message:"11112"
}
},
props:['parents'],
render(h,context){
console.log(context)
return <div >message</div>
},
mounted(){
console.log(80)
},
})
//可在页面中直接<comp></comp>使用
也可以写在.vue文件中,然后在引用过来
import Vue from "vue";
import Icon from "@/components/Icon.vue";
Vue.component("Icon", Icon);
# vue.component与vue.extend
Vue.extend({}) 简述:使用vue.extend返回一个子类构造函数,也就是预设部分选项的vue实例构造器。后可使用 vue.component 进行实例化或使用 new extendName().$mount(''+el) 方式进行实例化(从而实现模拟组件)。
let Footer = Vue.extend({
data(){
return {
footerName:'I CAN DO IT...'
}
},
template:'<div>{{footerName}}</div>'
});
用render函数写的jsx好像取不到extend里data的值
- Vue.component使用Vue.extend生成的构造函数
Vue.component('footer-view',Footer);
- 实例化构造函数从而模拟组件
new Footer({
data:{
'...':''
}
}).$mount('my-footer')
<template>
<my-footer></my-footer>
</template>
<script>
let Footer = Vuew.extend({
data(){
return {
footerName:'I CAN DO IT...'
}
},
template:'<div>{{footerName}}</div>'
});
Vue.component('footer-view',Footer);
// new Footer({
// data:{
// '...':''
// }
// }).$mount('my-footer')
</script>
- 构造函数实现: extend.js 合并
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name = extendOptions.name || Super.options.name
if (process.env.NODE_ENV !== 'production' && name) {
validateComponentName(name)
}
const Sub = function VueComponent (options) {
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(
Super.options,
extendOptions
)
Sub['super'] = Super
assets.js 循环组件 过滤器 指令 添加上去
this.options[type + 's'][id] = definition
# 组件化优点
- 复用性
- 更新时只更新当前局部的数据
- 测试更方便,开发更方便