1. 定义组件
语法:
Vue.extend({
template: ""
})
定义组件使用Vue.extend({})然后在里面定义一个template, 我们看到template的内容是html内容,
为了让html能够按照格式显示, 我们使用``将内容框起来
下面我们来注册一个组件
constcpnC = Vue.extend({
template: `
aaa
组件内容1
组件内容2
2. 注册组件
语法:
Vue.component("组件名称", 组件内容)
我们将上面定义的组件进行注册
// 2. 注册组件Vue.component('my-first-comp', cpnC)
3. 使用组件
直接使用组件名即可
完整源码:
Title
* 调用vue.extend()创建一个组件
* 传入的template代表我们自定义组件的模板
* vue2.x以后基本看不到这种写法, 会直接使用语法糖创建, 但原理还是这个.
*
* @type {VueComponent|void}
*/constcpnC = Vue.extend({
template: `
aaa
组件内容1
组件内容2
})
// 2. 注册组件Vue.component('my-first-comp', cpnC)
varapp =new Vue({
el: "#app",
data: {
message: "hello" }
});
二. 全局组件和局部组件
1. 全局组件
组件有全局组件和局部组件的概念, 如果将一个组件定义在外部就是全局组件
// 定义一个组件constmyComp = Vue.extend({
template: `
你好!!
})
// 注册组件(这种方式注册的组件是全局组件)Vue.component('my-comp', myComp)
let app =new Vue({
el: "#app",
data: {
message: "hello" }
});
第一步: 定义了一个组件
第二步: 注册组件, 在new Vue({})外面注册的, 是全局组件.
第三步: 调用组件
以上定义的就是一个全局组件. 全局组件什么概念呢? 也就是说任何一个Vue实例对象都可以使用.
下面定义了两个Vue对象
let app =new Vue({
el: "#app",
data: {
message: "hello" },
components:{
app1Comp: app1Comp
}
});
let app2 =new Vue({
el: "#app2" })
第一个作用对象是id="app"的div, 第二个作用对象是id="app2"的div
我们在里面调用组件, 都可以成功.
全局组件, 一次注册, 多处调用
2. 局部组件
constapp1Comp= Vue.extend({
template: `
只有app1才能使用的组件
})
let app =new Vue({
el: "#app",
data: {
message: "hello"},components:{
app1Comp: app1Comp
}});
我们定义了一个appComp的组件, 但是注册的时候, 只注册到了app这个Vue对象里, 那么就只有app能使用,其他vue对象不能使用, 这样的组件就是局部组件.
局部组件, 哪里注册, 哪里调用
三. 父组件和子组件
像这种有嵌套关系的组件, 就是父子组件.
那么父组件和子组件如何定义呢?
首先, 定义了一个组件1--comp1
// 定义组件1constcomp1 = Vue.extend({
template: `
组件1
})
然后定义了一个组件2---comp2
// 定义组件2constcomp2 = Vue.extend({
template: `
组件2
}})
我们发现, 在组件comp2中注册了comp1组件, 这里comp2是父组件, comp1是子组件.
最后我们可以把comp2注册到Vue对象上, 在页面就可以调用了
// vue也是一个组件, 是一个root根组件varapp =new Vue({
el: "#app",
data: {
message: "hello" },
components:{
comp2: comp2
}
});
vue也是一个组件, 是一个root根组件
四. 组件语法糖的写法
在vue2之后, 就很少看到Vue.extend({})的写法了, 而是使用语法糖
// 语法糖的写法Vue.component('comp2', {
template: '<div><h2>你好, 语法糖写法!</h2></div>'})
直接注册Vue组件
但是, 这么写会将html代码和组件纽在一起, 下面就说说如何将组件和模板分开
五. 模板和组件分离
我们有单独的方式定义模板代码. 有两种方法
第一种: script写法
组件和模板分离的写法1
使用script, 需要将type设置为text/x-template. 然后给模板设置一个id, 就代表一个模板了
然后, 注册模板
Vue.component('comp2', {
template: comp2
})
接下来就可以调用组件了
第二种: template写法
推荐使用第二种写法
组件模板分离的第二种写法
使用template标签, 并为其定义一个id, 组件的定义是一样的
Vue.component('comp3', {
template: comp3
})
五. 组件data关联的写法
组件中如果有变量, 怎么办呢? 我们知道在vue实例中, 变量可以定义在data中, 在组件中也有data属性, 但这个data属性是一个方法
例如: 我们定义了一个组件, 其中有一个变量title
这是一个组件:{{title}}
我们在注册组件的时候, 可以定义一个data函数, 并在返回值输出title属性
Vue.component('comp1', { template: comp1,data() {
return {
title: 'vue组件' }
}})
这样就可以拿到属性的值了. data()方法里面定义一个return返回值, 返回值是一个对象.
这样写有些奇怪是不是? 那为什么要写成方法呢?
协程组件, 我们的目的是复用, 在多处使用, 如果定义成一个变量值, 在一处修改, 其他调用的的地方也会跟着修改, 这不是我们希望看到的.
而方法是有作用域的, 每一个匿名方法都有自己的地址空间, 所以, 变量是不共享. 达到了相互隔离的目的.
那么, 如果就想共享怎么办呢? , 我们可以将变量提取出来. 如下写法:
// 如何让所有组件共享变量呢let shareData = {
title: "组件共有的title" }
Vue.component('comp2', {
template: comp2,
data(){
return shareData
}
})
这样每次返回的都是一个地址, 所以, 变量之间是共享的.
六. 父子组件的通信
什么是父子通讯呢? 我们来看看京东官网
可以吧这个页面看成是大组件, 里面有4个子组件构成: 上面是导航, 左边是栏目导航, 点击栏目导航右侧跟着变化.
我们来分析一下:
数据是在最外层的data里面, 然后循环遍历获取左侧导航, 当点击左侧导航的时候, 需要将参数传递给父组件, 然后发起新的请求, 在渲染到子组件中.
这就是父子通讯.
父子通讯分为父传子和子传父两种方式
1. 父传子组件的通讯
父子通讯有两种方式: 一种是数组, 一种是对象
我们在vue对象中定义了两个属性: message和languages
let app =new Vue({
el: "#app", data: {message:"父元素传递值给子元素111",languages:["go","php","python","java","c语言"]
}
});
然后要在模板中使用这两个属性, 要怎么样才能拿到属性呢?
在模板中使用props来接收属性, 使用props接收属性有两种方式:
1) 父子通讯方式---数组方式
第一种是使用数组的方式. 我们在数组中定义两个变量来接收Vue对象中的两个属性.
Vue.component("comp1", {
template: "#comp1",props:["clanguages","cmessage"]})
然后, 在模板里怎么写呢? 如下:
{{cmessage}}
- item in clanguages">{{item}}
接下来绑定组件变量和vue对象变量的关系, 在哪里调用组件, 就在哪里绑定
绑定的时候其实使用的是v-bind. 将组件的属性clanguage绑定到vue对象, 可以这么写:
:clanguages="languages"
这样就完成了绑定
其实总结有三步骤:
1. 在vue对象中定义属性
2. 在模板组件中定义与vue属性接收的变量
3. 在模板中绑定他们之间的关系
2) 父子通讯方式---对象方式
除了使用数组的方式来接收, 还可以使用对象的方式来接收
// props的对象写法Vue.component('comp2', {
template: "#comp2",
props:{
clanguages: {
type: Array, // 设置传值的类型必须是数组类型default: [],// 默认值是空数组required:true// 如果设置为true, 这个值必须传, 如果不传将报错 },
cmessage: {
type: String,
default:"aa",
required: true }
}
})
props接收的是一个对象, clanguages对象里面可以定义接收数据有三种
类型type,
默认值default
是否是必须有这个属性required: 这个属性的含义是, 调用了组件必须要使用这个属性.
其他使用方法可以参考文章: https://www.cnblogs.com/em2464/p/10418820.html
2. 子传父自定义事件
父传子使用的是定义属性接收, 而子传父使用的是定义事件的方式.
就使用上面的例子, 点击类型传参给父对象.
Vue.component('comp1', {
template: "#comp1",
data() {
return {
"types":[
{id:1, name:"手机类"},
{id:2, name:"日用品"},
{id:3, name:"空调类"},
{id:4, name:"电脑设备"},
{id:5, name:"家用电器"},
]
}
}
}
上面定义了一个组件, 组件定义了商城产品的类型
template id="comp1">
定义一个组件模板, 循环遍历商品类型, 并定义了一个点击事件. clicktype(item)
Vue.component('comp1', {
template: "#comp1",
data() {
return {
"types":[
{id:1, name:"手机类"},
{id:2, name:"日用品"},
{id:3, name:"空调类"},
{id:4, name:"电脑设备"},
{id:5, name:"家用电器"}, ] } },methods:{
clicktype(item) {
this.$emit('itemclick',item)
console.log("点击类型", item)
}
}})
在点击事件中, 我们使用this.$emit('itemclick', item)定义了一个事件, 并将元素对象item传递给了事件.
那么父组件如何接受这个事件呢?
父组件需要定义这个事件的监听. 通常我们都是监听点击事件click, 按键事件input等自带事件, 这里需要监听的是自定义事件
监听事件使用v-on:事件名称, 简写为@itemclick. 然后在父组件定义时间itemClick
varapp =new Vue({
el: "#app",
data: {
message: "hello"}, methods:{itemClick(item) {
console.log("传递事件到父组件", item)
}} });
这样就可以接收到子组件传递过来的数据了.
总结一下:
1. 在模板中定义一个事件, 调用this.$emit('事件名称', 传递参数....)
2. 在模板调用的时候监听事件. @事件名称="方法名()"
3. 在父组件中定义方法来接收事件监听.
案例源码:
Title
<!-- 2. 绑定事件 -->
<comp1 @itemclick="itemClick"></comp1>
template: "#comp1",
data() {
return {
"types":[
{id:1, name:"手机类"},
{id:2, name:"日用品"},
{id:3, name:"空调类"},
{id:4, name:"电脑设备"},
{id:5, name:"家用电器"}, ] } },methods:{ clicktype(item) {
// 1. 注册事件
this.$emit('itemclick',item)console.log("点击类型", item)
}
}})varapp =new Vue({
el: "#app",
data: {
message: "hello"}, methods:{
// 3.接收事件itemClick(item) {
console.log(
"传递事件到父组件", item)
}} });
亚马逊测评 www.yisuping.cn