组件化编程
模块:
向外提供特定供的JS程序,一般就是一个js文件。
作用:复用js,简化js的编写,提高js运行效率
组件:
实现应用中局部功能代码和资源的集合。
作用:复用编码,简化项目编码,提高运行效率
模块化:当应用中的js都以模块来编写时,那这个应用就是一个模块化应用。
组件化:当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用。
函数式和对象式的区别
对象式定义的对象,在被复用时会因为存在引用关系,修改一个引用时另一个引用也被改变。函数式定义的对象没有这个问题。
let data = {
a: 1,
b: 2
};
const x1 = data;
const x2 = data;
console.log(x1);
console.log(x2);
// data为对象式时, x1和x2引用同一个data对象。x1改变a属性时,x2的a属性也会被改
x1.a = 99;
console.log(x1.a);
console.log(x2.a);
function data2() {
return {
a: 1,
b: 2
}
}
const y1 = data2();
const y2 = data2();
console.log(y1);
console.log(y2);
// data2为函数式,y1、y2不存在引用关系。y1改变a属性时,不会影响y2的a属性
y1.a = 99;
console.log(y1.a);
console.log(y2.a);
非单文件组件
- 使用
Vue.extend
定义组件 - 将定义的组件注册进
new Vue
中 - 在页面中将组件名作为标签名配置到页面中
示例:
<body>
<div id="app">
<!-- 此处直接使用组件名作为标签名 -->
<school-component></school-component>
<hr>
<student-component></student-component>
</div>
</body>
<script>
Vue.config.productionTip = false;
// 定义组件
const school = Vue.extend({
// 组件中的配置项和new Vue中的配置项几乎一样
// 组件定义时不能写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器
// 使用template编写组件的模板
template: `
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
`,
// 组件中的data要使用函数式写法,不能使用对象式。使用函数式写法可以避免组件被附庸时存在引用关系
data(){
return {
schoolName: '庞各庄学院',
address: '庞各庄'
}
}
});
const student = Vue.extend({
template:
`
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
`,
data() {
return {
studentName: '张三',
age: 18
}
}
});
new Vue({
el: '#app',
components: {
'school-component': school, // 此处的定义的属性名才是真正的组件名,上面定义组件时的变量名只是一个临时的中转变量名
'student-component': student
}
});
</script>
注册全局组件:
<body>
<div id="app">
<hello></hello>
</div>
</body>
<script>
const hello = Vue.extend({
template:
`
<div>
<h2>{{msg}}</h2>
</div>`,
data() {
return {
msg: 'hello'
}
}
});
// 将组件注册为全局组件
// 参数1:组件名
// 参数2:组件
Vue.component('hello', hello);
new Vue({
el: '#app'
}
</script>
组件名注意点:
组件名为一个单词时:可以全小写,也可以首字母大写(推荐)
new Vue({
el: '#app',
components: {
Student: student // 单个单词时,可以首字母大写,也可以全小写
}
});
组件名为多个单词组成时:使用短横连接
new Vue({
el: '#app',
components: {
'my-student': student // 多个单词时,使用短横连接
}
});
如果是脚手架环境,可以使用所有单词首字母都大写的形式(推荐):
new Vue({
el: '#app',
components: {
MyStudent: student // 多个单词时,所有单词首字母都大写。(需要是脚手架环境才可以,引用vue.js是不可以处理首字母大写的)
}
});
组件名尽可能回避html中已经有的元素名称,例如:h2、H2等都不可以。
可以使用name
配置项指定组件在开发者工具中呈现的名字。例如:
<body>
<div id="app">
<student-component></student-component>
<hr>
</div>
</body>
<script>
Vue.config.productionTip = false;
const student = Vue.extend({
// 使用name属性配置该组件在Vue开发者工具中显示的名称。该名称不会影响组件在new Vue注册的名字。
name:'test',
template:
`
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
`,
data() {
return {
studentName: '张三',
age: 18
}
}
});
new Vue({
el: '#app',
components: {
'student-component': student
}
});
</script>
组件标签的写法:
<!-- 第一种写法:正常的双标签 -->
<school></school>
<!-- 第二种写法:自闭合 -->
<school />
第二种写法需要在脚手架环境下使用。如果不是脚手架环境,<school/>
会导致后续组件不能正确渲染。
组件配置的简写形式:
const school = Vue.extend(options);
// 可以简写为:
const school = options;
组件嵌套
组件可以嵌套使用,在父组件里嵌套子组件。
例如:
<body>
<div id="app">
<school></school>
</div>
</body>
<script>
Vue.config.productionTip = false;
const student = {
template:
`<div>
<h2>{{studentName}}</h2>
</div>`,
data() {
return {
studentName: 'tom'
}
}
}
// school内部嵌套student组件
const school = {
template:
`<div>
<h2>{{schoolName}}</h2>
<student></student>
</div>`,
data() {
return {
schoolName: '庞各庄小学'
}
},
components: {
student
}
}
new Vue({
el: '#app',
components: {
school
}
})
</script>
实际开发中,一般在vm中只有一个叫app
的组件,其他组件都嵌套进app
组件内。
例如:
<body>
<div id="app">
</div>
</body>
<script>
Vue.config.productionTip = false;
const student = {
template:
`<div>
<h2>{{studentName}}</h2>
</div>`,
data() {
return {
studentName: 'tom'
}
}
}
const school = {
template:
`<div>
<h2>{{schoolName}}</h2>
<student></student>
</div>`,
data() {
return {
schoolName: '庞各庄小学'
}
},
components: {
student
}
}
const hello = {
template:
`<div>
<h2>{{msg}}</h2>
</div>`,
data() {
return {
msg: 'hello'
}
}
}
// 其他组件位于app组件下
const app = {
template:
`<div>
<hello></hello>
<school></school>
</div>`,
components: {
hello,
school
}
}
// vm中只管理app一个组件
new Vue({
el: '#app',
template:`<app></app>`,
components: {
app
}
})
</script>
VueComponent
定义的组件在本质上是一个名为VueComponent
的构造函数,且不是开发人员定义的,是Vue.extend
生成的。
在模板中配置<school></school>
,Vue解析时会自动创建school
组件的实例对象。即Vue自动执行了new VueComponent(options)
。
每次调用Vue.extend
,返回的都是一个全新的VueComponent
。
Vue的this
指向:
- 在组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数,它们的
this
均是VueComponent
实例对象vc
- 在
new Vue
配置中,data函数、methods函数、watch中的函数、computed中的函数,它们的this
均是Vue实例对象vm
js原型对象
js中定义一个函数后,函数对象会有一个prototype
属性,称为显示原型属性。
如果该函数是一个构造函数,new 出来一个对象后,这个实例对象会有一个__proto__
属性,该属性称为隐式原型属性。
显示原型属性、隐式原型属性都指向了同一个对象,叫做原型对象。
对象的隐式原型属性(原型对象)指向自己的缔造者。
// 定义一个构造函数
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__); // true,这两个属性都指向了同一个对象,叫做原型对象
因为Demo.prototype
和d.__proto__
是同一个对象,所以操作Demo.prototype
时实例对象也会变:
Demo.prototype.x = 99;
console.log('d.__proto__.x:' + d.__proto__.x); // d.__proto__.x 也可以输出99
进一步的,如果程序中使用了d.x
,而d
对象本身没有x
属性,就会顺着原型链查找到d.__proto__.x
:
console.log('d.x:' + d.x); // d.x 也可以输出99。 d本身没有x属性,但是js会通过原型链d.__proto__找到d.__proto__.x
Vue组件中的内置关系
Vue组件中:Vue组件的原型对象的原型对象,就是Vue的原型对象
VueComponent.prototype.__proto__ === Vue.prototype
单文件组件
一个文件就是一个组件,组件的模板、样式、定义都在该文件中。
文件名后缀为.vue
,里面可以编写3个标签:
<template>
<!-- 组件的结构,即配置的组件模板 -->
</template>
<script>
// 组件交互相关的代码(数据、方法等)
</script>
<style>
/* 组件的样式 */
</style>
推荐为VSCode安装 Vetur
插件进行VUE代码的编写。
示例:
<template>
<!-- 组件模板 -->
<div class="demo">
<h2>{{studentName}}</h2>
</div>
</template>
<script>
// 定义组件
const school = Vue.extend({
name: 'School', // vue开发者工具中显示的名称
data() {
return{
studentName: 'tom'
}
}
});
// 将组件暴露出去。也可以使用其他export方式,推荐使用 export default 进行暴露
export default School;
</script>
<style>
.demo{
background-color: skyblue;
}
</style>
定义组件的位置一般使用简写:
<script>
// 简写形式:
// 不再定义临时的中转变量,直接在定义时就export出去
// 不再使用Vue.extend,使用简写形式直接编写options
export default {
name: 'School',
data() {
return{
studentName: 'tom'
}
}
}
</script>
实际开发中,会创建一个App
组件管理其他组件:
<template>
<div>
<school />
<student />
</div>
</template>
<script>
import School from './School'
import Student from './Student.vue'
export default {
name: 'App',
components: {School,Student}
}
</script>
<style>
</style>
另外,会创建一个main.js
作为入口文件,用来创建vm
实例:
import App from './App'
new Vue({
el: '#root',
template: `<app/>`,
comments: { App }
})
最后在页面中引入main.js
:
<!DOCTYPE html>
<html lang="en">
<head>
<title>首页</title>
</head>
<body>
<div id="root"></div>
<script src="./scripts/vue.js"></script>
<!-- 最好在body最下方引入main.js,此时页面已经加载 -->
<script src="./main.js"></script>
</body>
</html>
HTML的其他标签
html中的<head>
标签中,出现的<meta>
的含义:
<head>
<!-- 编码 -->
<meta charset="UTF-8">
<!-- 针对IE浏览器的一个特殊配置,含义是让IE浏览器以最高的渲染级别渲染页面 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 开启移动端的理想视口 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
html中的<noscript>
标签,如果浏览器不支持js则会渲染出来:
<body>
<noscript>
不好意思,您的浏览器不支持js。
</noscript>
</body>