组件是可复用的 Vue 实例,且带有一个名字
- 组件也是一个 vue 实例,可以传入和 vue 一样的属性
- 实例一个组件,这里只是定义一个组件,还没有再全局或者 vue 实例中注册,还不能去使用它
//1. 创建组件构造器
let Profile = Vue.extend({
//1.1 模板选项
template : `
<div>
<input type="date">
<p>今天心情不错!</p>
</div>
`
});
或者在 html 页面中用 template
或者 script
便签定义一个模板
<!-- 写在 vue 实例控制的区域外 -->
<template id="myTemplate">
<div>
<h1>今天心情不错</h1>
<p>出去走走</p>
</div>
</template>
<!--这样也可以定义一个vue组件-->
<script type="text/template" id="myTemplate">
<div>
<h1>今天心情不错</h1>
<p>出去爬山</p>
</div>
</script>
- 全局注册组件:这里全局注册的组件可以在页面上所有的vue实例中去使用
// 注册全局组件
Vue.component('mytemplate',Profile);
使用:以组件名称为一对标签的写入 vue 实例控制的界面即可
<div id="app">
<mytemplate></mytemplate>
</div>
- 局部注册组件:在 vue 实例的
components
属性中注册局部组件,局部组件只能在对应 vue 实例控制的区域内使用
//1. 创建Vue的实例
let vm = new Vue({
el : '#app',
data : {
message : ''
},
methods : {
//实例的所有函数实现
},
components : {
//注册局部组件,只能在这个vue实例内部使用
'mytemplate' : Profile
}
});
- 父子组件间传值问题,通过一个 TodoList 案例来解释,要求:在文本框中输入 Todo 添加到 list 中,点击 list 删除对应项,涉及到子组件向父组件传值和父组件向子组件传值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>TodoList</title>
<script src="../../Vue/node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="inputValue">
<button @click="addToList">提交</button>
<ul>
<todo-item v-for="(item, index) in list" :content="item" :index="index" @delete="deleteFromList">
</todo-item>
</ul>
</div>
<script>
// 注册一个 TodoItem 的组件
let todoItem = {
template: `<li @click="deleteItem">{{ content }}</li>`,
props: ['content', 'index'],
methods: {
deleteItem() {
this.$emit('delete', this.index);
}
}
};
let vm = new Vue({
el: '#app',
data: {
list: [],
inputValue: ''
},
methods: {
addToList() {
this.list.push(this.inputValue);
this.inputValue = '';
},
deleteFromList(index) {
this.list.splice(index, 1);
}
},
components: {
todoItem
}
});
</script>
</body>
</html>
子组件向父组件传值,用事件调用的方式,父组件向子组件传值用属性绑定的方式。
- 属性绑定:可以实现父组件向子组件传值,在做属性绑定时,一定要在子组件中的
props
中去定义这个属性,子组件才可以使用在子组件中,也可以对父组件传的值做一定的校验
// 可以将 props 属性写成一个对象
props:{
// 属性名
content : {
type: String, // 规定接收属性的类型,如果要接收多个属性,可以写成一个数组
required : Boolean, // 是否为必填,如果为 true 并且父组件没有传值则会报一个警告,默认是 false
default : defaultValue, // 默认值
validator : function (value) {
// 接收 属性的 value 值,可以对 value 进行验证,放回 true 表示通过验证, false 表示验证失败
}
}
}
- 事件调用:在子组件中调用
this.$emit('父组件自定义函数名',若干参数)
的方式触发父组件自定义函数中对用的父级函数,来达到子组件向父组件传递值的目的(函数调用时的参数传递) - 非父子组件间传值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>doucment</title>
</head>
<body>
<div id="app">
<mytemplate :content="'one'"></mytemplate>
<mytemplate :content="'two'"></mytemplate>
</div>
<script src="../../Vue/node_modules/vue/dist/vue.js"></script>
<script>
/*
组件间不可以直接传值,
我们可以将这个值放在一个公共的地方,
然后组件去拿,这个地方就是 Vue 的原型上
1. 我们在Vue构造函数原型上定义一个属性,职为一个vue实例
2. 在一个组件中用这个公共实例去触发一个自定义事件
this.bus.$emit('fnName', args)
3. 在另一个组件中去接收这个函数的触发,
通过回调函数的参数接收触发时传递的参数
this.bus.$on('fnName', function(args){
// handler
});
*/
Vue.prototype.bus = new Vue();
//1. 创建组件构造器
let Profile = {
//1.1 模板选项
template: `<div @click="clickHandler">{{ selfContent }}</div>`,
props: ['content'],
data() {
return {
/*
这里接收 content ,
因为我们需要去修改父组件的 content 的值,
如果是一 个引用类型,可能会造成问题 ,
影响别的组件对content的引用
需要先接收一下再修改
*/
selfContent: this.content
}
},
methods: {
clickHandler() {
// 让原型上的 bus 实例去触发事件一个事件
this.bus.$emit('change', this.selfContent);
}
},
mounted() {
this.bus.$on('change', msg => {
this.selfContent = msg;
});
},
};
// 2. 注册全局组件
Vue.component('mytemplate', Profile);
//1. 创建Vue的实例
let vm = new Vue({
el: '#app',
data: {
message: ''
},
methods: {
//实例的所有函数实现
}
});
</script>
</body>
</html>
- 如果我们在组件标签上想去触发一个原生 DOM 事件,直接写是不生效的
<div id="app">
<myComponent @click="clickHandler></myComponent>
</div>
我们原本的目的是想直接点击这个组件就可以触发原生的 click
事件,但是事与愿违,他会将我们写的 click
当成一个自定义事件去解析,如果需要作为一个原生的 DOM 事件去触发,我们可以添加一个修饰符即可
<myComponent @click.native="clickHandler></myComponent>
- 假如涉及到了复杂的组件间的传值问题,可以考虑使用 vuex
- 插槽的使用:如果我们需要由父组件向子组件里面传一段 html 代码,显然是不好取用属性绑定的方式,这里我们用插槽
<div id="app">
<my-slot>
<!--组件中写入的html代码为插槽部分的代码-->
<!--用slot给插槽命名,只会显示到组件中 name 属性为该名称的插槽中-->
<div slot="panel-body">
<img src="image.jpg" alt="">
<p>鞠婧炜</p>
</div>
</my-slot>
</div>
<template id="my-slot">
<div class="panel">
<h1 class="panel-heading">头部</h1>
<slot name="panel-body">默认显示!!!</slot>
<footer>尾部</footer>
</div>
</template>
- 组件向插槽传值,也是通过属性绑定的方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="../../Vue/node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<component>
<template slot-scope="props">
<p>this is a slot DOM</p>
<p>{{ props.msg }}</p>
</template>
</component>
</div>
<script>
let component = {
data() {
return {
msg: 'this is the component msg'
}
},
template: `<div>
<p>conponent DOM</p>
<slot :msg="msg"></slot>
</div>`
};
let vm = new Vue({
el: '#app',
components: {
component
}
});
</script>
</body>
</html>