版权声明:转载-复用,请联系博主微信:qiang510939237 https://blog.csdn.net/qiang510939237/article/details/89396338
组件 (重难点)
一 : 认识组件
什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可 (将一个完整的页面,抽离成一个个独立的组件,最终,通过这一个个独立组件完成整个的页面(项目)的功能)
组件化和模块化的不同:
- 模块化: 是从代码逻辑的角度进行划分的,方便代码分层开发,保证每个功能模块的职能单一
- 组件化: 是从UI界面的角度进行划分的,前端的组件化,方便UI组件的重用
- 组件化开发的优势/作用: 复用
二 : 全局组件定义的三种方式
-
使用 Vue.extend 配合 Vue.component 方法:
var login = Vue.extend({ template: '<h1>登录</h1>' }); Vue.component('login', login);
-
直接使用 Vue.component 方法:
Vue.component('register', { template: '<h1>注册</h1>' });
-
将模板字符串,定义到script标签种:
<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需要被定义为一个方法,例如:
Vue.component('account', {
template: '#tmpl',
data() {
return {
msg: '大家好!'
}
},
methods:{
login(){
alert('点击了登录按钮');
}
}
});
2. 在子组件中,如果将模板字符串,定义到了script标签中,那么,要访问子组件身上的data属性中的值,需要使用this来访问
三 : 组件的基本使用(基本)
先注册, 再使用
Vue 中的两种注册组件的方法:
1.全局注册 2.局部注册
全局组件在所有的vue实例中都可以使用
局部组件在所有的当前实例中可以使用
1.注册全局组件 - 基本使用
/**
* 第一个参数 : 组件名称
* 第二个参数 : 是一个配置对象, 该配置对象与 Vue 实例的配置对象几乎完全相同
* 也就是说: vue实例中用到的配置项,和组件中的配置项几乎相同
*/
Vue.component('child', {
template: `
<h1 class="red">这是child组件</h1>
`
})
- 注意点
- 注册全局组件也是放到 vm 实例之前
- 模板只能有一个根节点
- 组件的配置项和 vue 实例 的配置项一样 (如:data、methods、filters、watch、computed、钩子函数等)
- 组件的 data 是一个函数 , 并且返回一个对象
// 演示为什么vue在组件中的数据采用函数,而不是对象 ???
// 原因 : 只想让组件复用,不想让数据复用
// 不建议修改对象的属性,
var Component = function() {}
// 使用对象
Component.prototype.data = {
demo: 123
}
// 使用函数
Component.prototype.data = function() {
return {
demo: 111
}
}
var component1 = new Component()
var component2 = new Component()
component1.data().demo = '8888'
console.log(component2.data().demo) // 456
使用组件: - 当标签一样使用 <child></child>
2. 使用components属性定义局部子组件
// 引用组件
<div id="app">
<account></account>
</div>
// 组件实例定义方式:
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
components: { // 定义子组件
account: { // account 组件
template: '<div><h1>这是Account组件{{name}}</h1><login></login></div>', // 在这里使用定义的子组件
components: { // 定义子组件的子组件
login: { // login 组件
template: "<h3>这是登录组件</h3>"
}
}
}
}
});
</script>
四 : 组件通讯 (介绍)
导入: 演示子组件访问父组件数据,发现报错
- 组件是一个独立、封闭的个体
- 也就是说: 组件中的数据默认情况下, 只能在组件内部使用,无法直接在组件外部使用
- 可以将 vue 实例看做一个组件
- 对于组件之间需要相互使用彼此的情况,应该使用 **组件通讯机制** 来解决
- 组件通讯的三种情况 :
1. 父组件将数据传递给子组件 (父 => 子)
2. 子组件将数据传递给父组件 (子 => 父)
3. 非父子组件(兄弟组件)
五 : 父 ==> 子 (重点) 两步
1. 通过属性,父组件将要传递的数据,传递给子组件
<child :msg="pmsg"></child>
2. 子组件通过 props 配置项,来指定要接收的数据 (来定义父组件传递过来的数据)
props: ['msg']
// 以后使用
- 组件内: msg
- 事件中: this.msg
1. 组件实例定义方式,注意:一定要使用props属性来定义父组件传递过来的数据
<script>
// 创建 Vue 实例, 得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
msg: '这是父组件中的消息'
},
components: {
son: {
template: '<h1>这是子组件 --- {{finfo}}</h1>',
props: ['finfo']
}
}
});
</script>
2. 使用v-bind或简化指令,将数据传递到子组件中:
<div id="app">
<son :finfo="msg"></son>
</div>
六 : 子 ==> 父 (重点) 三步
-
原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去;
-
父组件将方法的引用传递给子组件,其中,getMsg是父组件中methods中定义的方法名称,func是子组件调用传递过来方法时候的方法名称
<son @func="getMsg"></son>
-
子组件内部通过this.$emit(‘方法名’, 要传递的数据)方式,来调用父组件中的方法,同时把数据传递给父组件使用
<div id="app"> <!-- 引用父组件 --> <son @func="getMsg"></son> <!-- 组件模板定义 --> <script type="x-template" id="son"> <div> <input type="button" value="向父组件传值" @click="sendMsg" /> </div> </script> </div> <script> // 子组件的定义方式 Vue.component('son', { template: '#son', // 组件模板Id methods: { sendMsg() { // 按钮的点击事件 this.$emit('func', 'OK'); // 调用父组件传递过来的方法,同时把数据传递出去 } } }); // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: { getMsg(val){ // 子组件中,通过 this.$emit() 实际调用的方法,在此进行定义 alert(val); } } }); </script>
1. 父组件中提供一个方法
pfn(arg) {
console.log('父组件中接受到子组件传递过来的数据:', arg)
}
2. 通过自定义事件, 父组件将这个方法传递给子组件
// 自定义事件 <child @fn="pfn"></child>
3. 子组件调用这个方法( 触发父组件中传递过来的自定义事件 )
// 在钩子函数里演示也可以,自己调用
created() {
// 调用父组件中的方法 pfn
// 注意:通过 $emit 方法来触发事件 fn
// 第一个参数:表示要触发的自定义事件名称,也就是 @fn
// 第二个参数:表示要传递给父组件的数据
this.$emit('fn', 'child msg')
}
七 : 目前为止可以存属性的地方
1. data
2. 计算属性
3. props
八 : 单向数据流(组件与组件之间) (了解)
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定: 父级 prop 的更新会向下流动到子组件中,但是反过来则不行.这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
- 透漏三个问题 :
- 组件与组件之间是单向数据流
- 父级 props 的更新会向下流动到子组件中
- 子组件不允许修改父组件传过来的prop数据
问题: vue 是单向的还是双向的 ?? (单向)
双向 (V <==> M) (v-model 语法糖,本质还是我给你,你给我)
单向 ( 组件 与 组件 )
九 : props 的特点 : (只读)
- 演示验证 props 只读
- 传的是简单类型 : 修改会报错
- 传的复杂类型 (地址) : 修改不会报错,是因为地址没有变 ,测试 obj={}立马报错
- 修改父组件传给子组件的数据
思路: 把接收过来的数据,保存到 data 中一个临时值 (适用在该组件接收数据只会在当前组件内使用)
Vue.component('child', {
template: `
<div>子组件 {{ cmsg }} </div>
`,
data() {
return {
cmsg: this.msg
}
},
props: ['msg'],
created() {
this.cmsg = 666
}
})