非单文件组件
非单文件组件就是一个文件里面有n个组件 n>1
Vue中使用组件的三大步骤:
一、定义组件(创建组件)
使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;
区别如下:
- el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
- data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
备注:使用template可以配置组件结构。
//第一步:创建school组件
const school = Vue.extend({
template:`
<div class="demo">
<h2>学校名称:{
{schoolName}}</h2>
<h2>学校地址:{
{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
`,
// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
data(){
return {
schoolName:'gcshi',
address:'陕西西安'
}
},
methods: {
showName(){
alert(this.schoolName)
}
},
})
二、注册组件
局部注册
靠new Vue的时候传入components选项
new Vue({
el:'#root',
data:{
msg:'你好啊!'
},
//第二步:注册组件(局部注册)
components:{
school,
}
})
全局注册
靠Vue.component('组件名',组件)
//第一步:创建hello组件
const hello = Vue.extend({
template:`
<div>
<h2>你好啊!{
{name}}</h2>
</div>
`,
data(){
return {
name:'Tom'
}
}
})
//第二步:全局注册组件
Vue.component('hello',hello)
三、使用组件(写组件标签)
vue.js为源码文件,以下文件直接进行了本地引入
链接:https://pan.baidu.com/s/1D8p8Ywxfo5PCIw_aF8xeNw
提取码:lhgv
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>基本使用</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<!-- 第三步:编写组件标签 -->
<hello></hello>
<hr>
<h1>{
{
msg}}</h1>
<hr>
<!-- 第三步:编写组件标签 -->
<school></school>
<hr>
<!-- 第三步:编写组件标签 -->
<student></student>
</div>
<div id="root2">
<hello></hello>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
//第一步:创建school组件
const school = Vue.extend({
template:`
<div class="demo">
<h2>学校名称:{
{schoolName}}</h2>
<h2>学校地址:{
{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
`,
data(){
return {
schoolName:'尚硅谷',
address:'北京昌平'
}
},
methods: {
showName(){
alert(this.schoolName)
}
},
})
//第一步:创建student组件
const student = Vue.extend({
template:`
<div>
<h2>学生姓名:{
{studentName}}</h2>
<h2>学生年龄:{
{age}}</h2>
</div>
`,
data(){
return {
studentName:'张三',
age:18
}
}
})
//第一步:创建hello组件
const hello = Vue.extend({
template:`
<div>
<h2>你好啊!{
{name}}</h2>
</div>
`,
data(){
return {
name:'Tom'
}
}
})
//第二步:全局注册组件
Vue.component('hello',hello)
//创建vm
new Vue({
el:'#root',
data:{
msg:'你好啊!'
},
//第二步:注册组件(局部注册)
components:{
school,
student
}
})
new Vue({
el:'#root2',
})
</script>
</html>
组件使用注意点
关于组件名:
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
备注:
(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
(2).可以使用name配置项指定组件在开发者工具中呈现的名字。
关于组件标签:
第一种写法:<school></school>
第二种写法:<school/> (需要使用脚手架,不用使用脚手架时,<school/>会导致后续组件不能渲染。)
一个简写方式
const school = Vue.extend(options) 可简写为:const school = options
组件的嵌套
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>组件的嵌套</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root"></div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//定义student组件
const student = Vue.extend({
name:'student',
template:`
<div>
<h2>学生姓名:{
{name}}</h2>
<h2>学生年龄:{
{age}}</h2>
</div>
`,
data(){
return {
name:'尚硅谷',
age:18
}
}
})
//定义school组件
const school = Vue.extend({
name:'school',
template:`
<div>
<h2>学校名称:{
{name}}</h2>
<h2>学校地址:{
{address}}</h2>
<student></student>
</div>
`,
data(){
return {
name:'尚硅谷',
address:'北京'
}
},
//注册组件(局部)
components:{
student
}
})
//定义hello组件
const hello = Vue.extend({
template:`<h1>{
{msg}}</h1>`,
data(){
return {
msg:'欢迎来到尚硅谷学习!'
}
}
})
//定义app组件
const app = Vue.extend({
template:`
<div>
<hello></hello>
<school></school>
</div>
`,
components:{
school,
hello
}
})
//创建vm
new Vue({
template:'<app></app>',
el:'#root',
//注册组件(局部)
components:{
app}
})
</script>
</html>
VueComponent
组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
//定义school组件 const school = Vue.extend({ name:'school', template:` <div> 哈哈哈哈 </div> `, }) console.log(school) // ƒ VueComponent (options) { // this._init(options); // }
从打印结果可以看出,shool组件实际是由VueComponent构造函数所实例化出来的对象。
打断点,进入vue.js源码中,可以发现在使用 Vue.extend创建组件时,实际还在内部调用了VueComponent构造函数生成了sub实例化对象,最终将实例化对象return了出来。我们只需要写或,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。
特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
关于this指向:
- 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>VueComponent</title> <script type="text/javascript" src="../js/vue.js"></script> </head> <body> <div id="root"> <school></school> <hello></hello> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false //定义school组件 const school = Vue.extend({ name:'school', template:` <h1 @click="showThis"> 点击school组件 </h1> `, methods: { showThis(){ console.log('school组件',this) } }, }) const test = Vue.extend({ template:`<h4>test子组件</h4>` }) //定义hello组件 const hello = Vue.extend({ template:` <h2> <h4>hello组件</h4> <test></test> </h2> `, components:{ test} }) //创建vm const vm = new Vue({ el:'#root', created(){ console.log("Vue根组件",this) }, components:{ school,hello} }) </script> </html>
此外。也可以看出,vue根组件管理者其他所有组件
VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm。
一个重要的内置关系
如图,正常情况下,VueComponent的隐式原型属性proto应该指向Object的原型对象,但是vue做了强制更改,使
VueComponent.prototype.proto === Vue.prototype
为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
vue2中的组件
原生html中组件的使用
不使用Cli脚手架的项目中
全局使用组件(全局注册)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>我的练习</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<my-Button></my-Button>
<my-Button></my-Button>
</div>
<script type="text/javascript">
// 定义一个名为 button-counter 的新组件
Vue.component('MyButton', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">我被点击了{
{ count }}次</button>'
})
const vm = new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>
组件名的两种命名方式
连字符:如 "my-Button",使用
驼峰式:如"MyButton",或均可。
- 直接在 DOM (即非字符串的模板) 中使用时只有连字符是有效的,如上述例子使用会报错
- 组件中的data必须是函数
局部使用组件(局部注册)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>我的练习</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<b>{
{
hello}}</b>
<my-Button1></my-Button1>
</div>
<script type="text/javascript">
const Bcomponent = {
data: function() {
return {
title: "嘿嘿!"}},
template: '<button>{
{ title }}</button>'
};
const Pcomponent = {
data: function() {
return {
count: 9}},
components:{
MyButton2:Bcomponent,
},
template: '<div><button>{
{ count }}次数</button><my-Button2></my-Button2></div>'
};
const vm = new Vue({
el: '#app',
data: {
hello:"你好"},
components:{
MyButton1:Pcomponent,
}
})
</script>
</body>
</html>
cli中组件的使用
通过cli创建的项目
全局使用组件(全局注册)
import Thecomponent from './Thecomponent.vue'
Vue.component('MyButton',Thecomponent )
const vm = new Vue({
render:h => h(App)
}).$mount("#app")
局部使用组件(局部注册)
某一vue文件中
<template>
<div class="app">
<Child></Child>
</div>
</template>
<script>
import Child from './components/Child.vue'//静态引入
export default {
name:'App',
components:{
Child:Child },
}
</script>
Vue3中组件
原生html中组件的使用
不使用Cli脚手架的项目中
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>我的练习</title>
</head>
<body>
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<button-counter></button-counter>
</div>
<script type="text/javascript">
// 创建一个Vue 应用
const app = Vue.createApp({
data() {
return {
counter: 0
}
}
})
// 定义一个名为 button-counter 的新全局组件
app.component('button-counter', {
data() {
return {
count: 0
}
},
template: `
<button @click="count++">
我被点击了 {
{ count }} 次
</button>`
})
app.mount('#app')
</script>
</body>
</html>
vite中
全局使用组件(全局注册)
const app = Vue.createApp({
...})
app.component('my-component-name', {
/* ... */
})
app.mount('#app')
局部使用组件(局部注册)
<template>
<div class="app">
<Child ></Child>
</div>
</template>
<script>
import Child from './components/Child.vue'//静态引入
export default {
name:'App',
components:{
Child}, //组件写法不变
}
</script>
方法同vue2,不变