定义Vue组件
什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可;
组件化和模块化的不同:
- 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
- 组件化: 是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;
一 全局组件定义的三种方式
-
使用 Vue.extend 配合 Vue.component 方法:
1.1 使用 Vue.extend 来创建全局的Vue组件 通过 template 属性,指定了组件要展示的HTML结构 var login = Vue.extend({ template: '<h1>登录</h1>' }); 1.2 使用 Vue.component('组件的名称', 创建出来的组件模板对象) Vue.component('mycom1', login); 1.3 如果要使用组件,标签形式,引入自己的组件 <mycom1></mycom1>
-
直接使用 Vue.component 方法:
定义: Vue.component('mycom2', { template: '<h1>注册</h1>' }); 使用: 如果要使用组件,标签形式,引入自己的组件 <mycom2></mycom2>
-
将模板字符串,定义到script标签种:
第二种的基础上方便HTML的编写<script id="tmpl" type="x-template"> <div><a href="#">登录</a> | <a href="#">注册</a></div> </script>
同时,需要使用 Vue.component 来定义组件:
Vue.component('account', { template: '#tmpl' });
注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!
二 组件中展示数据和响应事件
1. 组件可以有自己的 data 数据 和 methods
2. 组件的 data 和 实例的 data 有点不一样,实例中的 data 可以为一个对象,但是 组件中的 data 必须是一个方法
3. 组件中的 data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行;
4. 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!!
-
在组件中,
data
需要被定义为一个方法,而不是一个对象了。例如:Vue.component('account', { template: '<h1>这是全局组件 --- {{msg}}</h1>', data() { return { msg: '组件自己的数据' } }, methods:{ login(){ alert('点击了登录按钮'); } } });
-
在子组件中,如果将模板字符串,定义到了script标签中,那么,要访问子组件身上的
data
属性中的值,需要使用this
来访问;
【重点】为什么组件中的data属性必须定义为一个方法并返回一个对象
- 通过计数器案例演示
三 使用components
属性定义局部子组件
-
组件实例定义方式:
<script> // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, components: { // 定义子组件 account: { // account 组件 template: '<div><h1>这是Account组件{{name}}</h1></div>', // 在这里使用定义的子组件 components: { // 定义子组件的子组件 login: { // login 组件 template: "<h3>这是登录组件</h3>" } } } } }); </script>
-
引用组件:
<div id="app"> <account></account> </div>
四 使用flag
标识符结合v-if
和v-else
切换组件(只能切换2个)
-
页面结构:
<div id="app"> <input type="button" value="toggle" @click="flag=!flag"> <my-com1 v-if="flag"></my-com1> <my-com2 v-else="flag"></my-com2> </div>
-
Vue实例定义:
<script> Vue.component('myCom1', { template: '<h3>奔波霸</h3>' }) Vue.component('myCom2', { template: '<h3>霸波奔</h3>' }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { flag: true }, methods: {} }); </script>
五 使用:is
属性来切换不同的子组件,并添加切换动画(通过mode属性)
-
组件实例定义方式:
// 登录组件 const login = Vue.extend({ template: `<div> <h3>登录组件</h3> </div>` }); Vue.component('login', login); // 注册组件 const register = Vue.extend({ template: `<div> <h3>注册组件</h3> </div>` }); Vue.component('register', register); // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { comName: 'login' }, methods: {} });
-
使用
component
标签,来引用组件,并通过:is
属性来指定要加载的组件:<div id="app"> <a href="#" @click.prevent="comName='login'">登录</a> <a href="#" @click.prevent="comName='register'">注册</a> <hr> <transition mode="out-in"> <component :is="comName"></component> </transition> </div>
-
添加切换样式:
<style> .v-enter, .v-leave-to { opacity: 0; transform: translateX(30px); } .v-enter-active, .v-leave-active { position: absolute; transition: all 0.3s ease; } h3{ margin: 0; } </style>
六 父组件向子组件传值
-
组件实例定义方式,注意:一定要使用
props
属性来定义父组件传递过来的数据<script> // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { msg: '这是父组件中的消息' }, components: { son: { template: '<h1>这是子组件 --- {{finfo}}</h1>', props: ['finfo'] } } }); </script>
-
使用
v-bind
或简化指令,将数据传递到子组件中:通过 属性绑定(v-bind:) 的形式, 把 需要传递给 子组件的数据, 以属性绑定的形式,传递到子组件内部,供子组件使用 <div id="app"> <son :finfo="msg"></son> </div>
-
data与props的区别
注意1: 子组件中的 data 数据,并不是通过 父组件传递过来的,而是子组件自身私有的, 比如: 子组件通过 Ajax ,请求回来的数据,都可以放到 data 身上; 注意2: data 上的数据,都是可读可写的; props 中的数据,都是只读的,无法重新赋值
七 父组件向子组件传方法
1.定义一个字面量类型的 组件模板对象
2.创建vue实例,得到ViewModel,加载组件
3.template: 通过指定了一个 Id, 这个指定Id的 template 元素中的内容,当作 组件的HTML结构
4.在app控件中使用事件绑定机制传递方法
5.在子组件template模板中,通过自己的方法–调用传递进来的父组件的方法[this.$emit]
var com2 = {
template: '#tmpl', // 通过指定了一个 Id, 表示 说,要去加载 这个指定Id的 template 元素中的内容,当作 组件的HTML结构
data() {
return {
sonmsg: { name: '小头儿子', age: 6 }
}
},
methods: {
myclick() {
// 当点击子组件的按钮的时候,如何 拿到 父组件传递过来的 func 方法,并调用这个方法???
// emit 英文原意: 是触发,调用、发射的意思
// this.$emit('func123', 123, 456)
this.$emit('func', this.sonmsg)
}
}
}
=============================================
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
datamsgFormSon: null
},
methods: {
show(data) {
// console.log('调用了父组件身上的 show 方法: --- ' + data)
// console.log(data);
this.datamsgFormSon = data
}
},
components: {
com2
// com2: com2
}
});
=====================================
<div id="app">
<com2 @func="show"></com2>
</div>
=====================================
<template id="tmpl">
<div>
<h1>这是 子组件</h1>
<input type="button" value="这是子组件中的按钮 - 点击它,触发 父组件传递过来的 func 方法" @click="myclick">
</div>
</template>
八 子组件向父组件传值
-
原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
-
子组件内部通过
this.$emit('方法名', 要传递的数据)
方式,来调用父组件中的方法,同时把数据传递给父组件使用在子组件方法中传入参数 this.$emit('方法名', 123,456) data =123 data2 =456 在父类方法中接收参数 var vm = new Vue({ el: '#app', data: { datamsgFormSon: null }, methods: { show(data,data2) { // console.log('调用了父组件身上的 show 方法: --- ' + data + data2) this.datamsgFormSon = data } }
九 评论列表案例
目标:主要练习父子组件之间传值
十 使用 this.$refs
来获取元素和组件(获取dom元素)
<div id="app">
<div>
<input type="button" value="获取元素内容" @click="getElement" />
<!-- 使用 ref 获取元素 -->
<h1 ref="myh1">这是一个大大的H1</h1>
<hr>
<!-- 使用 ref 获取子组件 -->
<my-com ref="mycom"></my-com>
</div>
</div>
<script>
Vue.component('my-com', {
template: '<h5>这是一个子组件</h5>',
data() {
return {
name: '子组件'
}
}
});
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {
getElement() {
// 通过 this.$refs 来获取元素
console.log(this.$refs.myh1.innerText);
// 通过 this.$refs 来获取组件
console.log(this.$refs.mycom.name);
}
}
});
</script>