# 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")
			}
		}
	},
  1. 全局组件必须写在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根元素下面的,并且会报错。

  1. 模板里面第一级只能有一个标签,不能并行;
<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);

原文地址 (opens new window)

# 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

# 组件化优点

  • 复用性
  • 更新时只更新当前局部的数据
  • 测试更方便,开发更方便
最后更新: 12/7/2021, 7:11:09 PM