Vue组件的定义与注册
Vue组件的定义和注册
组件:组件(Component
)的出现就是为了拆分Vue实例的代码量,能够让我们以不同的组件来划分不同的功能模块,将来需要使用什么样的功能,就可以去调用对面的组件即可。(提高重用性,让代码可复用)
模块化与组件化的区别:
模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的只能单一
组件化:是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用
全局组件的定义和注册
组件Component
是Vue.js最强大的功能之一。组件可以扩展HTML元素,封装可重用的代码。
定义组件的三种方式(一)
写法一:使用Vue.extend
方法定义组件,使用Vue.compotent
方法注册组件
//component(s)
<body>
<div id="app">
<!-- 如果要使用组件,直接把组件的名称,以 HTML 标签的形式,引入到页面中,即可 -->
<account> </account>
</div>
<script>
//第一步:使用 Vue.extend 定义组件
var myAccount = Vue.extend({
template: '<div><h2>登录页面</h2> <h3>注册页面</h3></div>' // 通过 template 属性,指定了组件要展示的HTML结构。template 是 Vue 中的关键字,不能改。
});
//第二步:使用 Vue.component 注册组件
// Vue.component('组件的名称', 创建出来的组件模板对象)
Vue.component('account', myAccount); //第一个参数是组件的名称(标签名),第二个参数是模板对象
new Vue({
el: '#app'
});
</script>
</body>
注意:在注册时,若组件的名称是驼峰命名,那么在标签中使用组件时,需要将大写的驼峰改为小写的字母,同时两个单词之间用
-
连接。Vue.component('myComponent', myAccount);`//第一个参数是组件的名称(标签名),第二个参数是模板对象 `<my-component></my-component>`
- 为了避免名字不一致的问题,注册组件时,组件的名称可以直接写成
my-component
(避免驼峰不一致)
定义组件的三种方式(二)
写法二:Vue.component方法定义、注册组件(一步到位)
<body>
<div id="app">
<account> </account>
</div>
<script>
//定义、注册组件:第一个参数是组件的名称(标签名),第二个参数是组件的定义
Vue.component('account', {
template: '<div><h2>登录页面</h2> <h3>注册页面</h3></div>' // template 是 Vue 中的关键字,不能改。
});
new Vue({
el: '#app'
});
</script>
</body>
定义组件的三种方式(三)[推荐]
写法一、写法二不够智能,在定义模板的时候,不能智能提示和高亮,容易出错。
且template
·中的DOM结构必须被一个元素包含,如果直接写不被<div></div>
等包裹是无法渲染的
写法三:将组件内容定义到template
标签中
<body>
<!-- 定义模板 -->
<template id="myAccount">
<div>
<h2>登录页面</h2>
<h3>注册页面</h3>
</div>
</template>
<div id="app">
<!-- 使用组件 -->
<account> </account>
</div>
<script>
//定义、注册组件
Vue.component('account', {
template: '#myAccount' // template 是 Vue 中的关键字,不能改。
});
new Vue({
el: '#app'
});
</script>
</body>
使用components
定义私有组件(局部注册组件)
在一个Vue实例的内部定义私有组件,只有当前这个Vue实例才可以使用这个组件
<body>
<div id="app">
<!-- 使用Vue实例内部的私有组件 -->
<my-login></my-login>
</div>
<script>
new Vue({
el: '#app',
data: {},
components: { // 定义、注册Vue实例内部的私有组件
myLogin: {
template: '<h3>这是私有的login组件</h3>'
}
}
});
</script>
</body>
<body>
<hr>
<!-- 定义模板 -->
<template id="loginTmp">
<h3>这是私有的login组件</h3>
</template>
<hr>
<div id="app">
<!-- 调用Vue实例内部的私有组件 -->
<my-login></my-login>
</div>
<hr>
<script>
new Vue({
el: '#app',
data: {},
components: { // 定义、注册Vue实例内部的私有组件
myLogin: {
template: '#loginTmp'
}
}
});
</script>
</body>
template
为组件自定义的显示模块, 需要调用显示
/*局部注册组件示例测试完整代码*/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<my-login></my-login>
<br>
<my-logintwo></my-logintwo>
<br>
<my-loginthree></my-loginthree>
</div>
<template id="loginTmp">
<h3>局部注册的login组件测试壹</h3>
</template>
<script>
var LoginTmp2 = {
template: '<div>局部的login组件测试贰</div>',
}
var LoginTmp3 = Vue.extend({
template: '<h4>局部的login组件测试叁</h4>'
})
new Vue({
el: '#app',
data: {},
methods: {},
components: {
'myLogin' : {
template: '#loginTmp'
},
'myLogintwo': LoginTmp2,
'myLoginthree': LoginTmp3
}
});
</script>
</body>
</html>
使用is
属性挂载组件
Vue组件模板在某些情况下会受到HTML的限制,如<table>
内规定只允许是<tr>、<td>、<th>
等这些表格元素,所以在<table>
内直接使用组件是无效的。这种情况下可以使用特殊的is
属性来挂载组件。
<body>
<div id="app">
<table>
<tbody is="my-component"></tbody>
</table>
</div>
<script>
Vue.component('my-component', {
template: '<div>组件内容</div>'
})
new Vue({
el: '#app',
});
</script>
</body>
遇类似
<table> <ul> <ol> <select>
等限制元素可使用is
属性来挂载组件,元素内容会被替换为组件的内容
为组件添加data和methods
既然组件是一个页面,页面中可能会有一些需要动态展示可以通过为组件添加data
和methods
来实现
<body>
<!-- 定义组件的模板 -->
<template id="myAccount">
<div>
<!-- 在组件的模板中,调用本组件中的data -->
{{myData}}
<a href="#" v-on:click="login">登录1</a>
<h2>登录页面</h2>
<h3>注册页面</h3>
</div>
</template>
<div id="app">
<!-- 第一次调用组件模块 -->
<account> </account>
<!-- 第二次调用组件模块 -->
<account> </account>
</div>
<script>
//定义、注册组件
Vue.component('account', {
template: '#myAccount',
//组件中的 data
//【注意】组件中的data,不再是对象,而是一个方法(否则报错);而且这个方法内部,还必须返回一个对象才行
// 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!!
data: function () {
return {
myData: 'smyhvae'
}
},
//组件中的 method
methods: {
login: function () {
alert('login操作');
}
}
});
new Vue({
el: '#app'
});
</script>
</body>
上方代码中在account
中添加的data和methods,其作用域只限于account
组件里,保证独立性。
注意: 在为组件添加数据时,data不再是对象了,而是function,而且要通过return的形式进行返回;否则,页面上是无法看到效果的。通过function返回对象的形式来定义data,其作用是:
- 代码中
<account>
被调用了两次(不像根组件那样只能调用一次),但是每个组件里的数据myData
是各自独立的,不产生冲突 - 总之,通过函数返回对象的目的,是为了让每个组件都有自己独立的数据存储,而不应该共享一套数据。
为什么组件的data必须是一个function
<body>
<div id="app">
<!-- 第一次调用组件 -->
<counter></counter>
<hr>
<!-- 第二次调用组件 -->
<counter></counter>
</div>
<!-- 定义模板 -->
<template id="tmpl">
<div>
<input type="button" value="count加1" @click="increment">
<h3>{{count}}</h3>
</div>
</template>
<script>
var dataObj = { count: 0 }
// 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 +1
Vue.component('counter', {
template: '#tmpl',
data: function () {
return dataObj //当我们return全局的dataObj的时候,子组件们会共享这个dataObj
},
methods: {
increment() {
this.count++
}
}
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {}
});
</script>
</body>
运行效果:
上述代码将组件<counter>
调用了两次,由于dataObj
是全局对象,导致两个组件实例都可以共享这个dataObj
数据。所有我们点击任何一个组件实例,都会让所有count
+1
若想让<counter>
的两个实例去单独操作count
数据,需return一个新的对象数据。
// 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 +1
Vue.component('counter', {
template: '#tmpl',
data: function () {
// return dataObj //当我们return全局的dataObj的时候,这个dataObj是共享的
return { count: 0 } // 【重要】return一个**新开辟**的对象数据
},
methods: {
increment() {
this.count++
}
}
})
运行效果:
每当我们创建一个新的组件实例时,就会调用data函数,data函数里会return一个新开辟的对象数据。这样就能保证每个组件实例都有独立的数据存储
组件的切换
使用v-if
和v-else
结合falg进行切换
代码举例:(登录组件/注册组件,二选一)
<body>
<div id="app">
<!-- 温馨提示:`.prevent`可以阻止超链接的默认事件 -->
<a href="" @click.prevent="flag=true">登录</a>
<a href="" @click.prevent="flag=false">注册</a>
<!-- 登录组件/注册组件,同时只显示一个 -->
<login v-if="flag"></login>
<register v-else="flag"></register>
</div>
<script>
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
flag: false
},
methods: {}
});
</script>
</body>
运行效果:
使用Vue提供的<component>
标签实现组件切换
实现三个及以上的组件切换。
<body>
<div id="app">
<!-- 点击按钮后,设置变量`comName`为不同的值,代表着后面的component里显示不同的组件 -->
<a href="" @click.prevent="comName='login'">登录</a>
<a href="" @click.prevent="comName='register'">注册</a>
<!-- Vue提供了 component ,来展示对应名称的组件 -->
<!-- component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称 -->
<!-- 此处的`comName`是变量,变量值为组件名称 -->
<component :is="comName"></component>
</div>
<script>
// 组件名称是 字符串
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
comName: 'login' // 当前 component 中的 :is 绑定的组件的名称
},
methods: {}
});
</script>
</body>
多个组件切换时,通过mode
属性添加过渡动画
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(150px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
</style>
<body>
<div id="app">
<a href="" @click.prevent="comName='login'">登录</a>
<a href="" @click.prevent="comName='register'">注册</a>
<!-- 通过 mode 属性,设置组件切换时候的 过渡动画 -->
<!-- 【重点】亮点是 mode="out-in" 这句话 -->
<transition mode="out-in">
<component :is="comName"></component>
</transition>
</div>
<script>
// 组件名称是 字符串
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
comName: 'login' // 当前 component 中的 :is 绑定的组件的名称
},
methods: {}
});
</script>
</body>
多个组件切换时,如果要设置动画,可以用
<transition>
把组件包裹起来。需要注意的是,给<transition>
标签里添加了mode="out-in"
这种模式,它表示第一个组件消失之后,第二个组件才会出现。
transition中
mode
属性:
in-out
: 新元素先进行过渡,完成之后当前元素过渡离开
out-in
: 当前元素先进行过渡,完成之后新元素过渡进入