Vue学习笔记(2)(组件化开发)
Vue2.x学习笔记。原视频教程:最全最新Vue、Vuejs教程,从入门到精通_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
组件化
1. 什么是组件化?
组件化是Vue.js中的重要思想
它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
任何的应用都会被抽象成一颗组件树。
组件化思想的应用:
有了组件化的思想,我们在之后的开发中就要充分的利用它。
尽可能的将页面拆分成一个个小的、可复用的组件。
这样让我们的代码更加方便组织和管理,并且扩展性也更强。
2. 组件使用的基本步骤
组件的使用分成三个步骤:
创建组件构造器:
Vue.extend()
注册组件:
vue.component()
使用组件:在Vue实例的作用范围内使用组件
3. 全局组件和局部组件
当我们通过调用
Vue.component()
注册组件时,组件的注册是全局的- 这意味着该组件可以在任意Vue示例下使用。*
如果我们注册的组件是挂载在某个实例中, 那么就是一个局部组件
4. 父组件和子组件的区分
组件和组件之间存在层级关系,而其中一种非常重要的关系就是父子组件的关系:
**父子组件错误用法:**以子标签的形式在Vue实例中使用
因为当子组件注册到父组件的components时,Vue会编译好父组件的模块
该模板的内容已经决定了父组件将要渲染的HTML(相当于父组件中已经有了子组件中的内容了)
<child-cpn></child-cpn>
是只能在父组件中被识别的。类似这种用法,
<child-cpn></child-cpn>
是会被浏览器忽略的。
如果想要再使用子组件,必需重新注册:
let app = new Vue({el:'#app',components:{parent-cpn:parentComponent,child-cpn:childComponent}
})
5. 组件注册的语法糖
1)全局组件注册语法糖
//1.创建组件构造器
//const cpn1=Vue.extend()//2.注册组件(直接省略Vue.extend)
vue.component('cpn1',{template:`<div><p>test text</p></div>`
})
2)局部组件注册语法糖
const app = new Vue({el:'#app',components:{cpn2:{template:`<div><p>test text</p></div>`}}
})
6. 组件模板分离写法
我们通过语法糖简化了Vue组件的注册过程,另外还有一个地方的写法比较麻烦,就是template模块写法。
如果我们能将其中的HTML分离出来写,然后挂载到对应的组件上,必然结构会变得非常清晰。
Vue提供了两种方案来定义HTML模块内容:
使用
<script>
标签使用
<template>
标签
7. 组件中数据的存放
组件无法访问Vue实例中的数据,而且即使可以访问,如果将所有的数据都放在Vue实例中,Vue实例就会变的非常臃肿。
因此,Vue组件应该有自己保存数据的地方。
组件对象也有一个data属性(也可以有methods等属性,下面我们有用到)
只是这个data属性必须是一个函数
而且这个函数返回一个对象,对象内部保存着数据
<template><h2>{{title}}</h2>
</template><script>
Vue.compoment('cpn',{template:'#cpn',data(){return {title:'hello'}}
})
</script>
组件中的data为什么必须是函数
为什么data在组件中必须是一个函数呢?
首先,如果不是一个函数,Vue直接就会报错。
其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
8. 父子组件通信
我们知道子组件是不能引用父组件或者Vue实例的数据的。
但是,在开发中,往往一些数据确实需要从上层传递到下层:
比如在一个页面中,我们从服务器请求到了很多的数据。
其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。
这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)。
如何进行父子组件间的通信呢?Vue官方提到:
通过props向子组件传递数据
通过事件向父组件发送消息
1)父传子 - props
在组件中,使用选项props来声明需要从父级接收到的数据。
props的值有两种方式:
- 方式一:字符串数组,数组中的字符串就是传递时的名称。
- 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
方式一:
方式二:
当需要对props进行类型等验证时,就需要对象写法了。
当我们有自定义构造函数时,验证也支持自定义的类型。
关于props驼峰标识:
<div id="app"><!-- 这里不能直接使用cInfo驼峰命名,应使用 - 符号 --><cpn :c-info="info"></cpn> </div> <template id="cpn"><h2>{{cInfo}}</h2> </template><script> const cpn={template:"#cpn",props:{cInfo:{ //这里使用驼峰命名法type:Object,required:true}} }const app=new Vue({el:'#app',data:{info:{name:'nick',age:18}},components:{cpn} }) </script>
2)子传父(自定义事件)
什么时候需要自定义事件呢?
当子组件需要向父组件传递数据时,就要用到自定义事件了。
我们之前学习的
v-on
不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。
自定义事件的流程:
在子组件中,通过
$emit()
来触发事件。在父组件中,通过
v-on
来监听子组件事件。
<div id="app"><!-- 3:使用v-on监听子组件事件 --><cpn @item_click="cpnClick"></cpn>
</div>
<template id="cpn"><div><button v-for="item in lists" @click="btnClick(item)"> {{item}}</button></div>
</template><script>const cpn = {template: "#cpn",data() {return {lists: ['nick', 'jack', 'tom', 'jerry']}},methods:{//1:先在子组件中定义一个事件btnClick(item){//2:向父组件发射事件,携带参数this.$emit('item_click',item) //使用驼峰命名可能会发生问题}}}const app = new Vue({el: '#app',data: {},components: {cpn},methods:{//4:父组件中的事件,同时接收到参数cpnClick(item){console.log(item)}}})
</script>
3)结合双向绑定
<div id="app"><cpn :number="num" />
</div><template id="cpn"><div><h2>props:{{number}}</h2><h2>data:{{dnumber}}</h2><input type="text" v-model="dnumber"></div>
</template><script>const app = new Vue({el: '#app',data: {num: 1,},components: {cpn: {template: '#cpn',props: {//不应直接使用props的数据number: Number,},//使用data中的数据进行双向绑定data() {return {dnumber: this.number}}}}})
</script>
4)父访问子 - children/children/children/refs
1. $children
this.$children`是一个数组类型,它包含所有子组件对象。
<div id="app"><cpn></cpn><button @click="btnClick"></button>
</div><template id="cpn"><div>我是子组件</div>
</template><script>const app = new Vue({el: '#app',data: {},methods:{btnClick(){//打印所有的子组件对象console.log(this.$children);//调用第一个子组件的方法和属性this.$children[0].showMsg();console.log(this.$children[0].name)}},components: {cpn: {template: '#cpn',data() {return {name:'children'}},methods:{showMsg(){console.log('子组件msg')}}}}})
</script>
2. $refs
$children
的缺陷:
通过
$children
访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。
有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用
$refs
$refs
的使用:
$refs
和ref
指令通常是一起使用的。首先,我们通过
ref
给某一个子组件绑定一个特定的ID。其次,通过
this.$refs.ID
就可以访问到该组件了。
<child-cpn1 ref="child1"></child-cpn1>
<child-cpn2 ref="child2"></child-cpn2>
<button @click="showRefsCpn">通过refs访问子组件</button>
showRefsCpn(){console.log(this.$refs.child1.message);console.log(this.$refs.child2.message);
}
5)子访问父 - parent−parent-parent−root
注意事项:
尽管在Vue开发中,我们允许通过
$parent
来访问父组件,但是在真实开发中尽量不要这样做。子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了。
如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题。
另外,更不好做的是通过
$parent
直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于调试和维护。
访问根组件:
使用$root
访问根组件(也就是Vue实例)。
9. 插槽(slot)
slot翻译为插槽:
在生活中很多地方都有插槽,电脑的USB插槽,插板当中的电源插槽。
插槽的目的是让我们原来的设备具备更多的扩展性。
比如电脑的USB我们可以插入U盘、硬盘、手机、音响、键盘、鼠标等等。
组件的插槽:
组件的插槽也是为了让我们封装的组件更加具有扩展性。让使用者可以决定组件内部的一些内容到底展示什么。
例子:移动网站中的导航栏。
移动开发中,几乎每个页面都有导航栏。
导航栏我们必然会封装成一个插件,比如nav-bar组件。
一旦有了这个组件,我们就可以在多个页面中复用了。
但是每个页面的导航栏又不尽相同。
那如何封装合适呢?抽取共性,保留不同。
最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽。
一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容。
是搜索框,还是文字,还是菜单。由调用者自己来决定。
1)slot基本使用
在子组件中,使用特殊的元素<slot>
就可以为子组件开启一个插槽。
该插槽插入什么内容取决于父组件如何使用。
2)具名插槽
当子组件的功能复杂时,子组件的插槽可能并非是一个。
比如我们封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边。
那么,外面在给插槽插入内容时,如何区分插入的是哪一个呢?
这个时候,我们就需要给插槽起一个名字
如何使用具名插槽呢?非常简单,只要给slot元素一个name属性即可:
<slot name='myslot'></slot>
<body><div id="app"><cpn><!-- 尝试修改相应插槽内容 --><span slot="center">标题</span><button slot="right">返回</button></cpn></div><template id="cpn"><div><h2>我是子组件</h2><!-- 给插槽命名 --><slot name="left"><span>左边</span></slot><slot name="center"><span>中间</span></slot><slot name="right"><span>右边</span></slot></div></template>
</body><script>const app = new Vue({el: '#app',data: {},components: {cpn: {template: '#cpn',}}})
</script>
3)编译作用域
我们来考虑上面的代码是否最终是可以渲染出来的:
<my-cpn v-show="isShow"></my-cpn>
中,我们使用了isShow属性。isShow属性包含在组件中,也包含在Vue实例中。
答案:最终可以渲染出来,也就是使用的是Vue实例的属性。
官方给出了一条准则:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
而我们在使用
<my-cpn v-show="isShow"></my-cpn>
的时候,整个组件的使用过程是相当于在父组件中出现的。那么他的作用域就是父组件,使用的属性也是属于父组件的属性。
因此,isShow使用的是Vue实例中的属性,而不是子组件的属性。
4)作用域插槽
作用域插槽是slot一个比较难理解的点,而且官方文档说的又有点不清晰。
这里,我们用一句话对其做一个总结,然后我们在后续的案例中来体会:父组件替换插槽的标签,但是内容由子组件来提供。
我们先提一个需求:
子组件中包括一组数据,比如:pLanguages: [‘JavaScript’, ‘Python’, ‘Swift’, ‘Go’, ‘C++’]
需要在多个界面进行展示:某些界面是以水平方向一一展示的;某些界面是以列表形式展示的;某些界面直接展示一个数组
内容在子组件,希望父组件告诉我们如何展示,怎么办呢?利用slot作用域插槽就可以了
我们来看看子组件的定义:
在父组件使用我们的子组件时,从子组件中拿到数据:
我们通过
<template slot-scope="slotProps">
获取到slotProps(该名称随意)属性再通过
slotProps.data
(前面给子组件定义的什么属性名就用什么,这里子组件用的是:data
,所以用.data
)就可以获取到刚才我们传入的data了
Vue学习笔记(2)(组件化开发)相关推荐
- Vue学习笔记02 = 组件化
目录 一.组件化基本概念 什么是组件化?组件化有什么作用? 人面对复杂问题的处理方式: 组件化也是类似的思想: Vue组件化思想: 组件化思想的应用: 二.组件的基本使用: 2.1.创建组件的构造器. ...
- Vue学习笔记_组件化
文章目录
- vue(9)—— 组件化开发 - webpack(3)
前面两个终于把webpack相关配置解析完了.现在终于进入vue的开发了 vue组件化开发预热 前期准备 创建如下项目: app.js: footer.js: main.js: webpack.con ...
- Vue第二天学习总结—— Vue全家桶之组件化开发(组件化开发思想、组件注册、Vue调试工具用法、组件间数据交互传递、组件插槽、基于组件的案例——购物车)
(一) 组件化开发思想 1. 现实中的组件化思想体现 组件化即是对某些可以进行复用的功能进行封装的标准化工作 标准:要想组件能够成功组合在一起,每个组件必须要有标准 分治:将不同的功能封装到不同的组件 ...
- Vue全家桶之组件化开发
作者 | Jeskson 掘金 | https://juejin.im/user/5a16e1f3f265da43128096cb 学习组件化开发,首先掌握组件化的开发思想,组件的注册方式,组件间的数 ...
- Vue学习笔记05 组件的自定义事件-组件通信-$nextTick-脚手架解决ajax跨域-插槽-过渡动画
文章目录 Vue学习笔记05 父组件给子组件传值 注意点 子组件给父组件传值 父组件接受子组件的传值 通过函数 组件的自定义事件 事件绑定的第一种写法 @或v-on 事件绑定的第二种写法:使用ref ...
- Vue学习笔记之16-tarbar地开发思路
页面下方有一个单独的TabBar组件, 如何封装 自定义TabBar组件, 在App组件中使用 让TabBar处在底部, 并且在 .vue文件中的style标签中设置相关的样式 页面中会有很多公共的样 ...
- 【Vue】Vue学习笔记——UI组件库和常用插件
文章目录 6. UI组件库和常用插件 6.1 Element-ui 6.2 Vue-router 6.2.1 基本用法 6.2.2 跳转 6.2.3 路由嵌套 6.2.4 路由参数传递 6.3 Axi ...
- vue学习笔记(1)-组件通信
vue.js官方教程上讲的也挺清楚的了,自己整理一遍以加深印象,同时也完成自己的项目中需要的动态创建表单提交编辑修改功能. 表单主要是v-model双向绑定实现父组件与子组件的双向数据传递,所以首先说 ...
- Vue学习笔记(八) 组件进阶
1.插槽 (1)插槽内容 像 HTML 元素一样,我们常常需要给组件传递内容 比如在下面的例子中,我们给自定义组件 prompt-info 传入 出错啦 的文本 <!DOCTYPE html&g ...
最新文章
- Nature:运动能力与空间竞争驱动的细菌共存及机制解析
- 局部响应归一化(Local Response Normalization)
- ROW_NUMBER() OVER()函数用法;(分组,排序),partition by
- 继承thread类创建线程
- 你活了多久----快用Python计算一下日期
- Express+Socket.IO 实现简易聊天室
- 为什么现在的手机价格越来越高,最后一条真相了...
- SC || 记不住的正则
- DIV+CSS:页脚永远保持在页面底部
- 音乐的聆听 古典音乐的入门
- Hadoop安装详细教程 单机版
- 整合阿里云视频播放器——Coding在线(十四)
- Java进阶(二十九)集合12:集合练习题
- Palo Alto Networks 升级Traps高级终端防护产品 提升终端安全防护水平
- 机器学习处理信号分离_机器学习和深度学习现如今能应用在雷达信号处理,或者信号处理的哪些方面?...
- 怎样删除wps文档计算机信息,文本框删除,wps怎么删除文本框
- Docker 占用磁盘空间清理
- 在QQ远程协助为什么键盘无法输入?一起来学习!
- uniapp使用企业微信SDK踩坑指南
- 路由器有以下几种联网接口