组件化就是将一个页面拆成一个个可复用功能块(组件),方便扩展和复用.
注意:在实际开发中,我们并不会用以下方式开发组件,而是采用 vue-cli 创建 .vue 模板文件的方式开发,以下方法只是为了让大家理解什么是组件。
组件使用的三个步骤:
components
注册局部组件,只有注册的Vue实例才能使用,注册的Vue实例的父实例不能使用该局部组件组件是可复用的 Vue 实例,一般称new出来的Vue实例为根组件.
<div id="vue">
<ul>
<my-component-li v-for="item in items" v-bind:aaa="item">my-component-li>
ul>
div>
<script src="https://cdn.jsdelivr.net/npm/vue">script>
<script type="text/javascript">
const cpnc1 = Vue.extend({
template: `
啊啊啊啊
`
})
// 组件中注册组件
const cpnc2 = Vue.extend({
template: `
哈哈哈哈哈
`,
//组件构造器中注册组件,
components:{
cpn1: cpnc1
}
})
//注册组件 cpn1为组件名
Vue.component('cpn1',cpnc1)
// 使用语法糖注册组件,{}就是传入extend的对象
Vue.component('my-component-li', {
//使用 props 属性向子组件传递数据,通过v-bind绑定属性
props: ['aaa'],
//组件的模板
template: 'Hello {
{aaa}} '
});
var vm = new Vue({
el: '#vue',
data: {
items: ["张三", "李四", "王五"]
}
});
const app= new Vue({
el: '#app',
//注册局部组件
components: {
// cpn为使用组件的标签名,cpnc为组件构造器
cpn: cpnc2
// 使用语法糖可以省略 extend
cpu2: {
template: `
哈哈哈哈哈
`,
components:{
cpn1: cpnc1
}
}
}
})
script>
//type必须为 text/x-template
<script type="text/x-template" id="cpn">
<li>Hello</li>
script>
<script src="https://cdn.jsdelivr.net/npm/vue">script>
<script type="text/javascript">
Vue.component('myli', {
template: '#cpn'
});
script>
<template id="cpn">
<li>Helloli>
template>
<script src="https://cdn.jsdelivr.net/npm/vue">script>
<script type="text/javascript">
Vue.component('myli', {
template: '#cpn'
});
script>
<script type="text/javascript">
Vue.component('myli', {
template: '{
{title}}
',
data(){
return {
title: 'abc'
}
},
//组件中定义方法与Vue实例中一样
methods: {
}
});
// 强制组件创建的不同标签间data数据共享
const obj={
count: 0
}
Vue.component('myliii', {
template: '{
{count}}
',
data(){
return obj
}
});
script>
避免在子组件中直接改变props属性的值,而是在子组件中使用data或计算属性接收props属性的值后再进行双向绑定或修改
<div id="vue">
<ul>
<my-component-li v-for="item in items" v-bind:aaa="item">my-component-li>
ul>
div>
<script src="https://cdn.jsdelivr.net/npm/vue">script>
<script type="text/javascript">
Vue.component('my-component-li', {
//props可使用数组或对象
//使用数组只能指定变量名
//props: ['aaa'],
//使用对象时可指定类型,默认值,是否必传
//类型是对象或数组时,默认值必须是函数
// 还可验证自定义类型
props:{
// 只指定类型
aaa: String,
// 指定类型和默认值,必传值
bbb: {
type: String,
default: 'aaaaaa',
required: true
}
cage: Number,
cpp: {
type: Array,
default(){
return []
}
},
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return {
message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
template: 'Hello {
{aaa}} ',
data(){
return {
//将 props中的aaa赋值给data
daaa: this.aaa
}
}
});
var vm = new Vue({
el: '#vue',
data: {
items: ["张三", "李四", "王五"]
}
});
script>
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。所以使用驼峰命名法的 props 名需要使用其等价的短横线分隔命名
Vue.component('blog-post', {
// 在 JavaScript 中是 驼峰 的
props: ['postTitle'],
template: '<h3>{
{ postTitle }}h3>'
})
<blog-post post-title="hello!">blog-post>
this.$emit('自定义事件名', 参数)
设置自定义事件<div id="vue">
<myarr @itemclick="cpnclick">myarr>
div>
<template id="cpn">
<div>
<button v-for="item in items" @click="btnclick(item)">
{
{item}}
button>
div>
template>
<script src="https://cdn.jsdelivr.net/npm/vue">script>
<script type="text/javascript">
Vue.component('myarr', {
template: "#cpn",
data(){
return{
items: ["张三", "李四", "王五"]
}
},
methods: {
btnclick(item){
// 子组件获取到点击的按钮
console.log(item);
// 子组件向父组件发送指定事件
this.$emit('itemclick', item)
}
}
});
var vm = new Vue({
el: '#vue',
methods: {
cpnclick(item): {
// 父组件监听到事件
console.log('cpnclick',item);
}
}
});
script>
v-model
拆成v-bind:value
和input
事件,在不影响数据双向绑定的前提下,在input事件调用的方法中添加自定义事件完成子组件向父组件传值.v-model
+watch
实现,v-model完成数据的双向绑定,watch监听数据发生改变时执行自定义事件.props:{
name: ''
}
data(){
num: 0
}
// watch 监听props/data中数据的改变
// watch的属性名必须和props/data中的相同
// watch可得到新旧值,也可值得到新值
watch:{
name(newValue,oldValue){
},
num(newValue){
}
}
有时候我们需要父子组件之间可以直接访问,而不是仅仅传值通信
this.$children //返回子组件的数组
this.$children[0].方法名/data属性名 // 执行/获取第一个子组件的方法/属性值
this.$refs.aaa //获取指定的子组件
this.$refs.aaa.name //获取aaa子组件的name属性值
this.$parent //获取父组件
this.$root //获取根组件
在 Vue.js 中我们使用 元素作为承载分发内容的出口,作者称其为 插槽,可以应用在组合组件的场景中,相当于占位符,提高组件的扩展性.
Vue.component('chacao', {
template: '
默认值
'
});
传入的值
传入的值1
传入的值2
传入的值3
slot的name属性值 和 替换元素的slot属性值相等时,替换指定插槽
Vue.component('chacao', {
template: '
左
右
'
});
指定插槽替换
插槽的作用域:
定义一个名为 todo 的待办事项组件, 该组件中放置了两个插槽,分别为 todo-title 和 todo-items
Vue.component('todo', {
template: '
'
});
定义一个名为 todo-title 的待办标题组件
Vue.component('todo-title', {
props: ['title'],
template: '{
{title}}'
});
定义一个名为 todo-items 的待办内容组件
Vue.component('todo-items', {
props: ['item', 'index'],
template: '{
{index + 1}}. {
{item}} '
});
初始化
var vm = new Vue({
el: '#vue',
data: {
todoItems: ['《刀剑神域3》', '《关于我转生成为史莱姆这件事》', '《实力至上主义教室》']
}
});
父模板中的变量会使用父组件的属性,上面的div属于根组件的模板,会从根组件寻找变量而不是从子组件中寻找
slot-scope:作用域插槽
:让替换插槽的内容能够访问子组件中的数据
常用于父组件对子组件数据渲染方式不满意的情况下,获取到子组件的数据自行展示.
{
{slot.data}}
Vue.component('todo', {
template: '
',
data(){
return{
todoItems: ['《刀剑神域3》', '《关于我转生成为史莱姆这件事》', '《实力至上主义教室》']
}
}
});
var vm = new Vue({
el: '#vue'
});