组件化编程
组件化编程
- 理解: 用来实现局部(特定)功能效果的代码集合(html/css/js/image…..);
- 为什么: 一个界面的功能很复杂;
- 作用: 复用编码, 简化项目编码, 提高运行效率;
非单文件组件
一个文件中包含有 n 个组件
Vue 中使用组件的三大步骤:
- 定义组件(创建组件)
- 注册组件
- 使用组件(写组件标签)
准备好一个容器
<div id="root">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<hr />
<h2>学生姓名:{{name}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
如何定义一个组件?
使用 Vue.extend(options)
创建,其中 options
和 new Vue(options)
时传入的那个 options
几乎一样,但也有点区别;
区别如下:
el 不要写,为什么? ——— 最终所有的组件都要经过一个 vm 的管理,由 vm 中的 el 决定服务哪个容器。
data 必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
使用 template 属性可以配置组件结构,会替换掉真实 DOM。
// 创建 school 组件
const school = Vue.extend({
// el: "#root", 组件不需要 el 标签, 最终所有标签都会被一个 vm 管理
// data写成函数式
data() {
return {
name: "学校",
address: "深圳",
};
},
});
// 创建 student 组件
const student = Vue.extend({
data() {
return {
name: "小明",
age: "北京",
};
},
});
如何注册组件?
局部注册:靠 new Vue 的时候传入 components 选项
全局注册:靠 Vue.component('组件名',组件)
组件在使用时还需要一个基本的 HTML 结构, 可以使用 template
在组件内定义.
template
必须要有一个根 DOM
节点.
局部注册
添加 template
// 创建 school 组件
const school = Vue.extend({
// el: "#root", 组件不需要 el 标签, 最终所有标签都会被一个 vm 管理
// data 写成函数式
// 使用 template 属性可以配置组件结构
template: `
<div>
<h2>学校名称:{{ name }}</h2>
<h2>学校地址:{{ address }}</h2>
</div>`,
data() {
return {
name: "学校",
address: "深圳",
};
},
});
// 创建 student 组件
const student = Vue.extend({
template: `
<div>
<h2>学生姓名:{{ name }}</h2>
<h2>学生年龄:{{ age }}</h2>
</div>`,
data() {
return {
name: "小明",
age: "北京",
};
},
});
创建 vm, vm 需要在最后创建, 否则无法加载组件
// 创建 vm
new Vue({
el: "#root",
// 注册组件 局部注册
components: {
// 驼峰命名法会导致组件加载不到
myschool: school,
mystudent: student,
},
});
修改 root 容器
<div id="root">
<myschool></myschool>
<hr />
<mystudent></mystudent>
</div>
全局注册
编写一个容器
<div id="root2">
<hello></hello>
</div>
创建一个新组件
const hello = Vue.extend({
template: `
<h1>hello</h1>
`,
});
进行全局注册
// 全局注册
Vue.component("hello", hello);
创建一个新的 vm 绑定容器, 不注册局部组件
new Vue({
el: "#root2",
});
提示
关于组件名:
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(kebab-case 命名):"my-school" (需要引号)
第二种写法(CamelCase 命名):MySchool (需要 Vue 脚手架支持)
备注:
组件名尽可能回避 HTML 中已有的元素名称,例如:h2、H2 都不行。
可以使用
name
配置项指定组件在开发者工具中呈现的名字。
关于组件标签:
第一种写法:<school></school>
第二种写法:<school/>
备注:
不用使用脚手架时,<school/>
会导致后续组件不能渲染。
一个简写方式:
const school = Vue.extend(options)
可简写为:const school = options
嵌套组件
简单的组件嵌套
<body>
<div id="root">
<school />
</div>
</body>
<script>
// 创建 student 组件
const student = {
template: `
<div>
<h2>学生名称:{{ name }}</h2>
<h2>学生年龄:{{ age }}</h2>
</div>`,
data() {
return {
name: "小明",
age: 18,
};
},
};
// 创建 school 组件
const school = {
template: `
<div>
<h2>学校名称:{{ name }}</h2>
<h2>学校地址:{{ address }}</h2>
<student/>
</div>`,
data() {
return {
name: "学校",
address: "深圳",
};
},
components: {
student,
},
};
// 创建 vm
new Vue({
el: "#root",
// 注册组件 局部注册
components: {
school,
},
});
</script>
一般会定义一个 app
父组件管理所有子组件.
// 添加一个 app 组件来管理其他组件
const app = {
template: `
<div>
<school/>
<hello/>
</div>`,
components: {
school,
hello,
},
};
// 创建 vm
new Vue({
template: `<app/>`,
el: "#root",
// vm 只需要管理 app
components: {
app,
},
});
在 vm
中配置了 template
, DOM
容器什么都不用写了.(标准化开发)
<div id="root"></div>
VueComponent
关于 <div id="root">
<school></school>
<hello></hello>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
//定义school组件
const school = Vue.extend({
name: "school",
template: `
<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName">点我提示学校名</button>
</div>
`,
data() {
return {
name: "尚硅谷",
address: "北京",
};
},
methods: {
showName() {
console.log("showName", this);
},
},
});
const test = Vue.extend({
template: `<span>atguigu</span>`,
});
//定义hello组件
const hello = Vue.extend({
template: `
<div>
<h2>{{msg}}</h2>
<test></test>
</div>
`,
data() {
return {
msg: "你好啊!",
};
},
components: { test },
});
// console.log('@',school)
// console.log('#',hello)
//创建vm
const vm = new Vue({
el: "#root",
components: { school, hello },
});
</script>
school
组件本质是一个名为VueComponent
的构造函数,且不是程序员定义的,是Vue.extend
生成的。我们只需要写
<school/>
或<school></school>
,Vue
解析时会帮我们创建school
组件的实例对象,即Vue
帮我们执行的:new VueComponent(options)
。特别注意:每次调用
Vue.extend
,返回的都是一个全新的VueComponent
!!!!关于
this
指向:组件配置中:
data
函数、methods
中的函数、watch
中的函数、computed
中的函数, 它们的this
均是【VueComponent
实例对象】。new Vue(options)
配置中:data
函数、methods
中的函数、watch
中的函数、computed
中的函数, 它们的this
均是【Vue
实例对象】。
VueComponent
的实例对象,以后简称vc
(也可称之为:组件实例对象)。Vue
的实例对象,以后简称vm
。
内置关系
- 一个重要的内置关系:
VueComponent.prototype.__proto__ === Vue.prototype
- 为什么要有这个关系:让组件实例对象(
vc
)可以访问到Vue
原型上的属性、方法。
<body>
<!-- 准备好一个容器-->
<div id="root">
<school></school>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false; //阻止 vue 在启动时生成生产提示。
Vue.prototype.x = 99;
//定义school组件
const school = Vue.extend({
name: "school",
template: `
<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showX">点我输出x</button>
</div>
`,
data() {
return {
name: "尚硅谷",
address: "北京",
};
},
methods: {
showX() {
console.log(this.x);
},
},
});
//创建一个vm
const vm = new Vue({
el: "#root",
data: {
msg: "你好",
},
components: { school },
});
//定义一个构造函数
function Demo() {
this.a = 1;
this.b = 2;
}
//创建一个Demo的实例对象
const d = new Demo();
console.log(Demo.prototype); //显示原型属性
console.log(d.__proto__); //隐式原型属性
console.log(Demo.prototype === d.__proto__);
//程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
Demo.prototype.x = 99;
console.log("@", d);
</script>
单文件组件
单文件组件后缀名名为 vue
且文件内只支持三种标签.
<template>
<!--组件结构 -->
</template>
<script>
// 交互
</script>
<style>
/*样式*/
</style>
ES6 复习: 单文件组件需要暴露出来, 才能被引入.
三种暴露方式:
例如:
暴露
school
组件分别暴露
export const school = Vue.extend(option)
统一暴露
export {school}
默认暴露
export default {option}
引入方式:
分别暴露和统一暴露需要大括号引入
import {school} from './school'
默认暴露不需要
import school from './school'
创建一个 School.vue
<template>
<!-- -->
<div class="demo">
<h2>学校名称:{{ name }}</h2>
<h2>学校地址:{{ address }}</h2>
<button @click="showName">点我提示学校名</button>
</div>
</template>
<script>
export default {
// 编程规范: name 和 文件名一致
name: "School",
data() {
return {
name: "尚硅谷",
address: "北京昌平",
};
},
methods: {
showName() {
alert(this.name);
},
},
};
</script>
<style>
/**/
.demo {
background-color: orange;
}
</style>
创建 App.vue
<template>
<div>
<School></School>
<Student></Student>
</div>
</template>
<script>
//引入组件
import School from "./School.vue";
export default {
name: "App",
components: {
School,
},
};
</script>
单文件组件里无法创建vm
, 需要使用 main.js
创建.
import App from "./App.vue";
new Vue({
el: "#root",
template: `<App></App>`,
components: { App },
});
创建一个容器 index.html
.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>练习一下单文件组件的语法</title>
</head>
<body>
<!-- 准备一个容器 -->
<div id="root"></div>
</body>
</html>
运行需要脚手架支持.