1. 组件的使用:
- 创建组件构造器
- 注册组件
- 使用组件
1.创建组件构造器
const cpnC = Vue.extend({ template: ` <div> <h2>我是标题</h2> <p>我是内容</p> </div>` }) 复制代码
2.注册组件
Vue.component('my_cpn', cpnC) 复制代码
3.使用组件
<div id='app'> <my_cpn></my_cpn> <my_cpn></my_cpn> <my_cpn></my_cpn> </div> 复制代码
注:事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面的语法糖,但这种方式是学习后面方式的基础。
2. 全局组件和局部组件
全局组件,意味着可以在多个Vue的实例下面使用, 上面我们注册的组件就是全局组件。那么我们如何来注册局部组件呢?
我们需要在Vue实例下面注册
const app = new Vue({ el: '#app', data: { }, // 注册局部组件 components:{ my_cpn:cpnC } }) 复制代码
3.父组件和子组件
<div id='app'> <cpn2></cpn2> </div> 复制代码
// 1. 创建第一个组件(子组件) const cpnC1 = Vue.extend({ template: ` <div> <h2>我是标题1</h2> <p>我是内容1</p> </div> ` }) 复制代码
// 2. 创建第二个组件(父组件) const cpnC2 = Vue.extend({ template: ` <div> <h2>我是标题2</h2> <p>我是内容2</p> <cpn1></cpn1> </div> `, components: { cpn1: cpnC1 } }) 复制代码
const app = new Vue({ el: '#app', data: { message: '你好 Vue.js' }, components: { cpn2: cpnC2 } }) 复制代码
4. 注册组件语法糖
主要省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替
// 全局组件注册的语法糖 // 1. 创建组件构造器 // 2. 注册组件 Vue.component('cpn1', { template: ` <div> <h2>我是标题</h2> <p>我是内容</p> </div> ` }) 复制代码
5. 组件模板抽离的写法
<!-- 第一种:script标签,类型必须是text/x-template --> <script type="text/x-template" id="cpn1"> <div> <h2>我是标题</h2> <p>我是内容</p> </div> </script> 复制代码
<!-- 第二种:template标签 --> <template id="cpn2"> <div> <h2>我是标题1</h2> <p>我是内容1</p> </div> </template> <script src='../js/vue.js'></script> <script> 复制代码
Vue.component('cpn2', { template: "#cpn2" }) 复制代码
6. 组件可以访问Vue实例数据吗?
不能!组件是一个单独功能模块的封装:
这个模块有属于自己的HTML模板,也应该有属于自己的数据data。
那么组件自己的数据存放在哪里呢?
- 组件对象也有一个data属性(也可以有methods等属性)
- 只是这个data属性必须是一个函数
- 而且这个函数返回一个对象,对象内部保存着数据
Vue.component('cpn2', { template: "#cpn2", data() { return { title: "abc" } } }) 复制代码
为什么data必须是函数?
因为保证多个组件使用时,各个组件之间不会相互影响。
7. 父子组件的通信、
在上一节我们提到了子组件是不能引用父组件或者Vue实例的数据的。
但是,在开发中,往往一些数据确实需要从上层传递到下层:
- 比如在一个页面上,我们从服务器请求到了很多的数据。
- 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。
- 这个时候我们并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)那么如何进行父子组件间的通信呢?
- 通过props向子组件传递数据
- 通过事件向父组件发送信息
props基本用法
- 在组件中,使用选项props来声明需要从父级接收到的数据。
- props的值有两种方式
- 方式一:字符串数据,数组中的字符串就是传递时的名称
- 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等方式一:
方式二:
通过事件向父组件发送信息
this.$emit()
<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: 1, name: "橙子" }, { id: 2, name: "苹果" }, { id: 3, name: "香蕉" }, { id: 4, name: "西瓜" }, ] } }, methods: { btnclick(item) { this.$emit('itemclick', item) } }, } const app = new Vue({ el: '#app', data: { message: '你好 Vue.js' }, components: { cpn }, methods: { cpnclick(item) { console.log('cpnclick', item) } }, }) </script> 复制代码
8.父子组件的访问方式:$children
- 父组件访问子组件:使用$children或$refs
- 子组件访问父组件:使用$parent
<body> <div id='app'> <cpn></cpn> <cpn></cpn> <cpn></cpn> <cpn ref="aaa"></cpn> <button @click="btnclick">按钮</button> </div> <template id="cpn"> <div> <h1>我是子组件</h1> </div> </template> <script src='../js/vue.js'></script> <script> const app = new Vue({ el: '#app', data: { message: '你好 Vue.js' }, methods: { btnclick() { // console.log(this.$children[0].showmessage); console.log(this.$refs.aaa.name);; } }, components: { 'cpn': { template: '#cpn', data() { return { name: '橙子' } }, methods: { showmessage() { console.log('showmessage') } }, } } }) </script> </body> 复制代码
<body> <div id='app'> <cpn></cpn> </div> <template id="cpn"> <div> <ccpn></ccpn> </div> </template> <template id="ccpn"> <div> <h1>我是cpn组件</h1> <button @click="btnclick">按钮</button> <h3>我是子组件</h3> </div> </template> <script src='../js/vue.js'></script> <script> const app = new Vue({ el: '#app', data: { message: '你好 Vue.js' }, components: { 'cpn': { template: '#cpn', data() { return { name: "橙子" } }, components: { 'ccpn': { template: '#ccpn', methods: { btnclick() {// 访问父组件$parent // console.log(this.$parent.name) // 访问根组件$root console.log(this.$root.message); } }, } } } } }) </script> </body> 复制代码
9.插槽的基本使用
<body> <div id='app'> <cpn> <h4>1111</h4> </cpn> <cpn> <h4>2222</h4> </cpn> <cpn></cpn> <cpn></cpn> </div> <template id="cpn"> <div> <h2>Vue真有意思</h2> <p>哈哈哈</p> <slot><button>按钮</button></slot> </div> </template> <script src='../js/vue.js'></script> <script> const app = new Vue({ el: '#app', data: { message: '你好 Vue.js', }, components: { 'cpn': { template: '#cpn' } } }) </script> </body> 复制代码
具名插槽
<body> <div id='app'> <cpn><button slot="medium">我是中间按钮</button></cpn> <cpn><button slot="right">我是右边按钮</button></cpn> </div> <template id="cpn"> <div> <h2>具名插槽的使用</h2> <slot name="left"><span>左边</span></slot> <slot name="medium"><span>中间</span></slot> <slot name="right"><span>右边</span></slot> </div> </template> <script src='../js/vue.js'></script> <script> const app = new Vue({ el: '#app', data: { message: '你好 Vue.js' }, components: { 'cpn': { template: '#cpn' } } }) </script> </body> 复制代码
编译作用域
<body> <div id='app'> <cpn v-show=isShow></cpn> </div> <template id="cpn"> <div> <h2>我是子组件</h2> <p v-show=isShow>我是内容嘿嘿嘿</p> </div> </template> <script src='../js/vue.js'></script> <script> const app = new Vue({ el: '#app', data: { message: '你好 Vue.js', isShow: true }, components: { cpn: { template: "#cpn", data() { return { isShow: false } } } } }) </script> </body> 复制代码
官方准则:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译
作用域插槽
比较难理解,有一句话概括一下
- 父组件替换插槽的标签,但是内容由子组件来提供
<body> <div id='app'> <cpn> <template slot-scope="slot"> <span v-for="item in slot.data">{{item}}-</span> </template> </cpn> <cpn> <template slot-scope="slot"> <span v-for="item in slot.data">{{item}}-</span> </template> </cpn> <cpn> <template slot-scope="slot"> <span>{{slot.data.join('*')}}</span> </template> </cpn> </div> <template id="cpn"> <div> <h1>我是子组件</h1> <slot :data=planguage> <ul> <li v-for="item in planguage">{{item}}</li> </ul> </slot> </div> </template> <script src='../js/vue.js'></script> <script> const app = new Vue({ el: '#app', data: { message: '你好 Vue.js' }, components: { cpn: { template: '#cpn', data() { return { planguage: ['JavaScript', 'Java', 'Python', 'C++', 'Swift'] } } } } }) </script> 复制代码