文章目录
- 什么是组件化 ❓
- 组件化目的 📇
- 组件使用3步骤 🕒
- 全局组件和局部组件 🍓
- 父子组件 🎨
- 注册组件语法糖 🍬
- 组件模板抽离的写法 ✍🏼
- 为什么组件data必须是函数 ❓
- 父子组件通信 父传子props ✉️
- 父子组件通信 props驼峰标识 🛑
- 父子组件通信 子传父自定义事件 🥳
什么是组件化 ❓
组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:
组件化目的 📇
组件使用3步骤 🕒
♦️ 创建组件构造器
♦️ 注册组件
♦️ 使用组件
<body>
<div id="app">
<!-- 3.使用组件 -->
<hello></hello>
<hello></hello>
</div>
<script src="./vue.js"></script>
<script>
// 1.插件组件构造器
const hello = Vue.extend({
template: `<div>
<h1>
Hello World
</h1>
</div>`
})
// 2.注册组件
Vue.component('hello',hello)
const vm = new Vue({
el: '#app'
})
</script>
</body>
全局组件和局部组件 🍓
全局注册
<body>
<div id="app">
<!-- 3.使用组件 -->
<hello></hello>
<hello></hello>
</div>
<div id="app1">
<hello></hello>
</div>
<script src="./vue.js"></script>
<script>
// 1.插件组件构造器
const hello = Vue.extend({
template: `<div>
<h1>
Hello World
</h1>
</div>`
})
// 2.注册组件(全局注册,意味着可以在多个vue实例下使用)
Vue.component('hello',hello)
const vm = new Vue({
el: '#app'
})
const vm1 = new Vue({
el:'#app1'
})
</script>
</body>
局部注册
<body>
<div id="app">
<!-- 3.使用组件 -->
<hello></hello>
<hello></hello>
</div>
<div id="app1">
<hello></hello>
</div>
<script src="./vue.js"></script>
<script>
// 1.插件组件构造器
const hello = Vue.extend({
template: `<div>
<h1>
Hello World
</h1>
</div>`
})
// 2.注册组件(全局注册,意味着可以在多个vue实例下使用)
const vm = new Vue({
el: '#app',
// 局部注册,只能在当前 vue 实例下使用
components:{
hello:hello
}
})
const vm1 = new Vue({
el:'#app1'
})
</script>
</body>
父子组件 🎨
<body>
<div id="app">
<c2></c2>
</div>
<script src="./vue.js"></script>
<script>
// 创建第一个组件
const c1 = Vue.extend({
template: `
<div>
<p>我是p1</p>
</div>
`
})
// 创建第二个组件
const c2 = Vue.extend({
template: `
<div>
<p>我是p2</p>
<c1></c1>
<c1></c1>
</div>
`,
components: {
c1: c1
}
})
new Vue({
el: '#app',
data: {
message: 'Hello World'
},
components: {
c2: c2
}
})
</script>
</body>
注意如果在vue实例下写标签 c1 是不正确的,因为我们既没有全局注册 c1 组件,也没有在 vue 实例中进行注册,而是在 c2 组件内部进行了注册,作用域在 c2 组件,所以可以在 c2 的模板中使用,这一点需要注意
注册组件语法糖 🍬
<body>
<div id="app">
<hello></hello>
</div>
<script src="./vue.js"></script>
<script>
// 全局注册,语法糖,底层还是 extend
Vue.component('hello',{
template:`
<div>
<h1>Hello World</h1>
</div>
`
})
new Vue({
el: '#app'
})
</script>
</body>
<body>
<div id="app">
<hello></hello>
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el: '#app',
components:{
hello:{
template:`
<div>
<h1>Hello World</h1>
</div>
`
}
}
})
</script>
</body>
组件模板抽离的写法 ✍🏼
<body>
<div id="app">
<hello></hello>
<world></world>
</div>
<!-- 1. 模板在script标签中写,但是类型必须是 text/x-template 类型 -->
<script type="text/x-template" id="hello">
<div>
<h2>Hello Vue</h2>
</div>
</script>
<!-- 2. 使用template标签 -->
<template id="world">
<div>
<h2>Hello World</h2>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.component('hello',{
template:'#hello'
})
Vue.component('World',{
template:'#world'
})
new Vue({
el: '#app',
})
</script>
</body>
为什么组件data必须是函数 ❓
<body>
<div id="app">
<hello></hello>
</div>
<template id="hello">
<div>
<h2>{{hello}}</h2>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.component('hello', {
template: '#hello',
data() {
return {
hello: 'Hello World,Hello Vue.js'
}
}
})
new Vue({
el: '#app',
})
</script>
</body>
<body>
<div id="app">
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<template id="counter">
<div>
<button @click="sub">-</button>
{{count}}
<button @click="add">+</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.component('counter', {
template: '#counter',
data() {
return {
count: 0
}
},
methods: {
add() {
this.count++;
},
sub() {
this.count--;
}
},
})
new Vue({
el: '#app',
})
</script>
</body>
<body>
<div id="app">
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<template id="counter">
<div>
<button @click="sub">-</button>
{{obj.count}}
<button @click="add">+</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const obj = {
count: 0
}
Vue.component('counter', {
template: '#counter',
data() {
return {
obj
}
},
methods: {
add() {
this.obj.count++;
},
sub() {
this.obj.count--;
}
},
})
new Vue({
el: '#app',
})
</script>
</body>
父子组件通信 父传子props ✉️
<body>
<div id="app">
<child :cmessage="message" :cmovies="movies"></child>
</div>
<template id="child">
<div>
<p>我是子组件</p>
<p>{{cmessage}}</p>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const child = {
template: '#child',
// 数组写法
// props: ['cmessage']
// 对象写法,还可以指定类型,
props: {
cmessage: {
// 类型
type: String,
// 默认值
default: '哈哈',
// 必须传值,否则报错
required: true
},
cmovies: {
type: Array,
default() {
return [];
}
}
}
}
new Vue({
el: '#app',
data: {
message: '你好啊,子组件',
movies: ['天气之子', '你的名字', '千与千寻']
},
components: {
child
}
})
</script>
</body>
父子组件通信 props驼峰标识 🛑
<body>
<div id="app">
<npm :c-npm="person"></npm>
</div>
<template id="npm">
<div>
<p>{{cNpm.width}}</p>
<p>{{cNpm.height}}</p>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const npm = {
template: '#npm',
props: {
cNpm: {
type: Object
}
}
}
new Vue({
el: '#app',
components: {
npm
},
data: {
person: {
height: 1.8,
width: 1.5
}
}
})
</script>
</body>
父子组件通信 子传父自定义事件 🥳
<body>
<!-- 父组件模板 -->
<div id="app">
<!-- 监听自定义事件,接收到事件触发后调用aa函数 -->
<hello @cclick="aa"></hello>
</div>
<!-- 子组件模板 -->
<template id="zi">
<div>
<button v-for="item in shoppings" @click="btnClick(item.name)">{{item.name}}</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
// 子组件
const hello = {
template: '#zi',
data() {
return {
shoppings: [
{ id: 'a', name: '热门推荐' },
{ id: 'b', name: '家用电器' },
{ id: 'c', name: '数码办公' }
]
}
},
methods: {
btnClick(name) {
// 自定义事件 cclick
this.$emit('cclick', name)
}
},
}
// 父组件
new Vue({
el: '#app',
components: {
hello
},
methods: {
aa(name) {
console.log(name);
}
}
})
</script>
</body>