组件化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<!-- 组件化:
如果我们将一个页面中所有的逻辑处理全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及拓展
我们将一个完整的页面分成很多个组件。每个组件都用于事件页面的一个功能块。而每一个组件又可以进行细分
Vue组件化思想:
它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用
任何的应用都会被抽象成一颗组件树
组件使用三个步骤:
创建组件构造器
注册组件
使用组件
-->
<div id="app">
<my-cpn></my-cpn>
<my-cpn></my-cpn>
<my-cpn></my-cpn>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建组件的构造器对象
// 传入template代表我们自定义组件模板,垓模板就是使用到组件的地方要显示的html代码
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
</div>`
});
// 2.注册组件
// 将构造器注册为一个组件,并且给他起一个组件标签名称 (注册组件的标签名,组件构造器)
// 这里注册的是全局组件
// Vue.component('my-cpn', cpnC);
// 组件必须挂载在vue实例下,否则不会生效
const app = new Vue({
el: '#app',
data: {
},
components: {
// 局部组件 这里是因为中间有一个‘-’,所以使用引号将其引起来
'my-cpn': cpnC
}
})
</script>
</body>
</html>
父组件和子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<div id="app">
<cpn2></cpn2>
<!-- <cpn1></cpn1> -->
<cpn3></cpn3>
<cpn4></cpn4>
<cpn5></cpn5>
</div>
<template id="cpn5">
<div>
<h2>我是标题5</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 子组件
const cpnC1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
</div>`
});
// 语法糖 全局组件
Vue.component('cpn3', {
template: `
<div>
<h2>我是标题3</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
</div>`
})
// 将模板提出去
Vue.component('cpn5', {
template: '#cpn5'
})
// 父组件
const cpnC2 = Vue.extend({
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
<cpn1></cpn1>
</div>`,
components: {
cpn1: cpnC1
}
});
// root组件
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn2: cpnC2,
//要想直接使用cpn1必须再注册
cpn1: cpnC1,
cpn4: {
template: `
<div>
<h2>我是标题4</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
</div>`
}
}
})
</script>
</body>
</html>
组件通信-父传子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<div id="app">
<cpn5></cpn5>
<cpn :cmovies="movies" :cmessage="message"></cpn>
<cpn :cmovies="movies"></cpn>
<!-- 当前版本props不支持驼峰命名,需要使用横线 cInfo c-info -->
<cpn :c-info="info"></cpn>
</div>
<template id="cpn5">
<div>
<h2>{{title}}</h2>
<p>我是内容,哈哈哈哈哈</p>
<p>我是内容,哈哈哈哈哈</p>
</div>
</template>
<template id="cpn">
<div>
<h2>{{cmessage}}</h2>
<h2>{{cmovies}}</h2>
<h2>{{cInfo}}</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 组件对象里面有一个data属性,只是这个data必须是一个方法,而这个方法返回一个对象,对象内部保存着数据
// 这样返回一个对象,保证了每次调用组件都是不同的对象,如果data是属性的话,就相当于返回的同一内存地址,是同一对象
Vue.component('cpn5', {
template: '#cpn5',
data() {
return {
title: '我是标题5'
}
}
})
// 通过props向子组件传递数据
// 通过事件向父组件发送消息
const cpn = {
template: '#cpn',
// 数组写法,引号里的是变量,不是字符串
// props: ['cmovies','cmessage']
// 对象写法,可以指定属性值类型
props: {
// 支持的类型:String,Number,Boolean,Array,Object,Date,Function,Symbol
// cmovies: Array,
// cmessage: String
// 提供一些默认值
cmessage: {
// 设置类型
type: String,
// 设置默认值
default: 'aaaaa',
// 是否必传属性
required: false
},
cmovies: {
type: Array,
// 类型是数组或者是对象时,默认值必须是一个函数
default() {
return [];
}
},
cInfo: {
type: Object,
default() {
return {};
}
}
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟'],
info: {
name: 'jxd',
age: 23,
height: 170
}
},
components: {
cpn
}
})
</script>
</body>
</html>
组件通信-子传父
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<!-- 父组件模板 -->
<div id="app">
<!-- 父组件可以监听子组件发射的事件 如果调用方法不传值,就是默认子组件发射的参数 -->
<cpn @itemclick="cpnClick"></cpn>
</div>
<!-- 子组件模板 -->
<template id="cpn">
<div>
<button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data() {
return {
categories: [
{ id: 'aaa', name: '热门推荐' },
{ id: 'bbb', name: '手机数码' },
{ id: 'ccc', name: '家用电器' },
{ id: 'ddd', name: '电脑办公' },
]
}
},
methods: {
btnClick(item) {
// console.log(item);
// 向父组件发射一个事件 —— 自定义事件,事件命,参数
this.$emit('itemclick', item);
}
}
}
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn
},
methods:{
cpnClick(item){
console.log(item);
}
}
})
</script>
</body>
</html>
父子组件双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<div id="app">
<cpn :number="num" @numchange="numChange" />
</div>
<template id="cpn">
<div>
<h2>props:{{number}}</h2>
<h2>data:{{dnumber}}</h2>
<!-- <input type="text" v-model="dnumber"> -->
<input type="text" :value="dnumber" @input="numInput">
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
num: 1
},
methods: {
numChange(value) {
// 字符串转数字
// this.num = Number(value);
this.num = parseInt(value);
}
},
components: {
cpn: {
template: '#cpn',
props: {
number: Number
},
data() {
return {
dnumber: this.number
}
},
methods: {
numInput(event) {
// 将input中的value赋值到dnumber中
this.dnumber = event.target.value;
// 为了让父组件可以修改值,发生一个事件
this.$emit('numchange', this.dnumber);
}
},
// 监听可以监听props,data中的值
watch:{
}
}
}
})
</script>
</body>
</html>
组件访问-父访问子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<div id="app">
<div>
<cpn></cpn>
<cpn></cpn>
<cpn ref="aaa"></cpn>
<button @click="btnclick()">按钮</button>
</div>
</div>
<template id="cpn">
<div>
{{name}}
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
},
methods: {
btnclick() {
// this.$children 获取子组件对象,是一个数组 用的比较少,因为数组通过下标去取不好
/* for (let c of this.$children) {
console.log(c);
c.showMessage();
console.log(c.name);
} */
// this.$refs 是对象 默认是一个空对象,需要在组件标签上添加 ref属性 如:ref="aaa"
console.log(this.$refs.aaa.name);
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是一个子组件'
}
},
methods: {
showMessage() {
console.log('showMessage');
}
}
}
}
})
</script>
</body>
</html>
组件访问-子访问父
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>{{name}}</h2>
<button @click="btnclick">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
name: 'jxd'
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: '我是子组件'
}
},
methods: {
btnclick() {
// 1.访问父组件 $parent
console.log(this.$parent);
console.log(this.$parent.name);
// 2.访问根组件 $root
console.log(this.$root);
console.log(this.$root.name);
}
}
}
}
})
</script>
</body>
</html>
组件插槽
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<div id="app">
<cpn><span>不使用插槽默认值</span></cpn>
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
<!-- 具名插槽 只会替换有名字的 -->
<cpn1><span slot="center">标题</span></cpn1>
</div>
<!-- 组件插槽:
为了让我们封装的组件更加具有拓展性
让使用者可以决定组件内部的一些内容到底展示什么
-->
<template id="cpn">
<div>
<h2>我是组件</h2>
<p>我是组件,哈哈哈哈</p>
<!-- 插槽可以传入默认值 如果有指定,就显示指定的 -->
<slot><button>按钮</button></slot>
</div>
</template>
<!-- 具名插槽 -->
<template id="cpn1">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot me="right"><span>右边</span></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn: {
template: '#cpn'
},
cpn1: {
template: '#cpn1'
}
}
})
</script>
</body>
</html>
编译作用域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<div id="app">
<cpn v-show="isShow"></cpn>
</div>
<!-- 父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译 -->
<template id="cpn">
<div>
<h2>我是子组件</h2>
<p>我是内容,哈哈哈哈</p>
<button v-show="isShow">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isShow: true
},
components: {
cpn: {
template: '#cpn',
data() {
return {
isShow: false
}
}
}
}
})
</script>
</body>
</html>
作用域插槽
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn>
<!-- 目的获取子组件的pLanguages -->
<!-- vue 2.5.x 一下需要使用templatek获取 :data中的值 -->
<template slot-scope="slot">
<!-- <span v-for="item in slot.data">{{item}} - </span> -->
<span>{{slot.data.join(' - ')}}</span>
</template>
</cpn>
</div>
<!-- 父组件替换插槽的标签,但是内容由子组件来提供 -->
<template id="cpn">
<div>
<!-- 这里的 :data 可以随便取名 如 :abc 使用的时候就是slot.abc -->
<slot :data="pLanguages">
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn: {
template: '#cpn',
data() {
return {
pLanguages: ['JavaScript', 'C++', 'Java', 'C#', 'Python', 'Go']
}
}
}
}
})
</script>
</body>
</html>