十一、组件化开发
1、组件化的实现和使用步骤
1.1、什么是组件化?
如果将一个复杂的问题,拆分成很多个可以处理的小问题,再将其放在整体当中,就会将问题迎刃而解
组件的定义:实现应用中局部功能代码和资源的集合
组件化思想:将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么整个页面的管理和维护就变得非常容易了
1.2、Vue组件化思想
组件树:
1.3、注册组件的基本步骤
组件的使用分成三个步骤:
- 创建组件构造器
- 注册组件
- 使用组件
- Vue.extend():
- 调用 Vue.extend() 创建的是一个组件构造器
- 通常在创建组件构造器时,传入 template 代表我们自定义组件的模板
- 该模板就是在使用到组件的地方,要显示的HTMl代码
- Vue.component():
- 调用Vue.component() 是将刚才的组件构造器注册为一个全局组件,并且给它起一个组件的标签名称。
- 所以需要传递两个参数:1、注册组件的标签名 2、组件构造器
- 组件必须挂载在某个Vue实例下,否则它不会生效
1.4、组件创建原理
Vue组件创建原理:https://blog.csdn.net/qq_53810245/article/details/122894319
2、全局组件和局部组件
3、父组件和子组件
组件嵌套:https://blog.csdn.net/qq_53810245/article/details/122891352
app 管理所有父组件,父组件中再嵌套子组件
理解:在root组件中定义父级组件,在父级组件中定义子组件,从而形成调用关系
4、注册组件语法糖
4.1、全局组件注册的语法糖
4.2、局部组件注册的语法糖
5、组件模板抽离写法
一般使用第二张模板
6、父子组件的通信
在开发中,旺旺一些数据需要从上层传递到下层:比如在一个页面中,我们从服务器请求到了很多的数据。其中一部分数据,并非是我们整个页面的大组件来展示,而是需要下面的子组件进行展示,这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)
通过 props 【properties属性】向子组件传递数据,通过事件向父组件发送消息
7、父传子——props数据验证
<div id="app">
<cpn :c-Info="info"></cpn>
</div>
<template id="cpn">
<h2>{
{cInfo.name}}</h2>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template:'#cpn',
props:{
cInfo:{
type:Object,
default() {
return {
};
}
}
}
}
const app = new Vue({
el: '#app',
data: {
info:{
name:'why',
age:18,
height:1.88
}
},
components:{
cpn
}
})
</script>
8、子传父——自定义事件
当子组件需要向父组件传递数据时,就要用到自定义事件】
自定义事件的流程
- 在子组件中,通过
$emit()
来触发事件 - 在父组件中,通过
v-on
来监听子组件事件<!--父组件的模板--> <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> // 1. 子组件 const cpn = { template:'#cpn', data(){ return{ categories:[ { id:101,name:'热门推荐'}, { id:102,name:'手机数码'}, { id:103,name:'电脑办公'}, { id:104,name:'家用家电'}, ] } }, methods:{ btnClick(item){ // console.log(item.id); // 发射事件:自定义事件,自定义发出的函数,自定义的参数 this.$emit('itemclick',item); } } } // 2. 父组件 const app = new Vue({ el:'#app', components:{ cpn }, methods: { cpnClick(item){ console.log('cpnClick',item) } } }) </script>
9、父子组件的访问
9.1、父组件访问子组件:使用 $children 或 $refs
- $ children 的访问
- this.$children 是一个数组类型,它包含所有子组件对象
- $ children 的访问
9.2、子组件访问父组件:使用 $parent 或 $root
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子访问父-parent-root</title>
</head>
<body>
<!--父组件的模板-->
<div id="app">
<cpn></cpn>
</div>
<!--子组件的模板-->
<template id="cpn">
<div>
<h2>我是子组件</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
// 注册子组件
components:{
cpn:{
template:'#cpn',
methods:{
btnClick(){
// 1.访问父组件 $parent,获取到的层级关系是VueComponents,以上为Vue实例
// console.log(this.$parent);
// 2. 访问根组件$root,获取到的是Vue实例
console.log(this.$root.message);
}
}
}
},
})
</script>
</body>
</html>
10、插槽 slot :抽取共性,保留不同
- slot 译为插槽,例如电脑的USB插槽、插板中的电源插槽
- 插槽的目的是让我们原有的设备更多的扩展性
- 组件的插槽
- 组件的插槽是为了让我们封装的组件更加具有扩展性
- 让使用者可以决定组件内部的一些内容到底展示什么
- 插槽的应用:
- 移动网站中的导航栏
- 导航栏会封装成一个插件,比如 nav-bar 组件
- 一旦有了这个组件,我们就可以在多个页面中复用了
10.1、插槽的基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>slot-插槽的基本使用</title>
</head>
<body>
<div id="app">
<cpn ref="ref"></cpn>
<cpn><button>跳转</button></cpn>
<cpn><button>点击</button></cpn>
<cpn><input type="text"></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子组件</h2>
<p>我是组件哈哈哈</p>
<!-- 预留插条,并在cpn标签下进行自行定义使用-->
<!-- <slot></slot>-->
<!-- 插条中也可以使用 默认的值,如重新定义插条中的内容即可覆盖原默认内容-->
<slot><button>按钮</button></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
methods:{
},
// 注册组件
components:{
cpn:{
template:'#cpn',
data(){
return{
}
}}}
})
</script>
</body>
</html>
10.2、具名插槽的使用
- 具名插槽:具有名字的插条
- 作用:针对 slot 插槽编排名字,可以实现指定替换
<div id="app">
<AAA>
<span slot="center">更改</span>
</AAA>
</div>
<template id="cpn">
<!-- <div>
<h2>这行代码我是不会更改的</h2>
<slot><button>默认按钮</button></slot>
</div>-->
<div>
<slot name="left"><span>左</span></slot>
<slot name="center"><span>中</span></slot>
<slot name="right"><span>右</span></slot>
<slot></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
},
components:{
cpn:{
template:'#cpn'
}
}
})
- 如果想要在插槽中存放多个内容但又不想用一个div将他们包裹起来,可以用如下方法,但必须添加绑定
- 父组件
- 子组件
10.3、编译作用域与作用域插槽的使用
- 编译作用域:在哪里定义的变量只会在它的作用域下进行查找调用
- 官方解释:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子集作用域内编译
作用域插槽的使用:父组件替换插槽的标签,但是内容由子组件来提供
例如:
十二、模块化开发
前言:随着 ajax 异步请求的出现,慢慢形成了前后端的分离
模块化的核心:导入与导出
1、CommonJS 导入与导出
2、ES模块化的导入与导出
导入导出使用前提:
2.1、导出
导出变量
- 方式一:边定义边导出
export var num = 1000 export let name = 'why' export const height = 1.88 // 导出函数/类: export function sum(num1,num2){ return num1 + num2 } export class Person{ constructor(name,age) { this.name = name; this.age = age; } run(){ console.log(this.name + '在奔跑'); } }
方式二:先定义后导出
var num = 1000 let name = 'why' const height = 1.88 // 导出函数/类: function sum(num1,num2){ return num1 + num2 } class Person{ constructor(name,age) { this.name = name; this.age = age; } run(){ console.log(this.name + '在奔跑'); } } export { num,name,height,sum,Person}
2.2、导入
import{
num1,height} from "./aaa.js";
或 统一全部导入
import * as all from "./aaa.js";
console.log(all.flag)
2.3、export default
- 某些情况下,给函数或功能不命名,在导入的时候导入者自己命名
需注意: export defalut 在同一个模块中,不允许同时存在多个
```js
export default function (args){
console.log(args);
}
导入
import fun from './aaa.js'
fun('快快打印')
```