组件化编程

模块:

向外提供特定供的JS程序,一般就是一个js文件。

作用:复用js,简化js的编写,提高js运行效率

组件:

实现应用中局部功能代码和资源的集合。

作用:复用编码,简化项目编码,提高运行效率

模块化:当应用中的js都以模块来编写时,那这个应用就是一个模块化应用。

组件化:当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用。

函数式和对象式的区别

对象式定义的对象,在被复用时会因为存在引用关系,修改一个引用时另一个引用也被改变。函数式定义的对象没有这个问题。

  1. let data = {
  2. a: 1,
  3. b: 2
  4. };
  5. const x1 = data;
  6. const x2 = data;
  7. console.log(x1);
  8. console.log(x2);
  9. // data为对象式时, x1和x2引用同一个data对象。x1改变a属性时,x2的a属性也会被改
  10. x1.a = 99;
  11. console.log(x1.a);
  12. console.log(x2.a);
  13. function data2() {
  14. return {
  15. a: 1,
  16. b: 2
  17. }
  18. }
  19. const y1 = data2();
  20. const y2 = data2();
  21. console.log(y1);
  22. console.log(y2);
  23. // data2为函数式,y1、y2不存在引用关系。y1改变a属性时,不会影响y2的a属性
  24. y1.a = 99;
  25. console.log(y1.a);
  26. console.log(y2.a);

非单文件组件

  1. 使用Vue.extend定义组件
  2. 将定义的组件注册进new Vue
  3. 在页面中将组件名作为标签名配置到页面中

示例:

  1. <body>
  2. <div id="app">
  3. <!-- 此处直接使用组件名作为标签名 -->
  4. <school-component></school-component>
  5. <hr>
  6. <student-component></student-component>
  7. </div>
  8. </body>
  9. <script>
  10. Vue.config.productionTip = false;
  11. // 定义组件
  12. const school = Vue.extend({
  13. // 组件中的配置项和new Vue中的配置项几乎一样
  14. // 组件定义时不能写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器
  15. // 使用template编写组件的模板
  16. template: `
  17. <div>
  18. <h2>学校名称:{{schoolName}}</h2>
  19. <h2>学校地址:{{address}}</h2>
  20. </div>
  21. `,
  22. // 组件中的data要使用函数式写法,不能使用对象式。使用函数式写法可以避免组件被附庸时存在引用关系
  23. data(){
  24. return {
  25. schoolName: '庞各庄学院',
  26. address: '庞各庄'
  27. }
  28. }
  29. });
  30. const student = Vue.extend({
  31. template:
  32. `
  33. <div>
  34. <h2>学生姓名:{{studentName}}</h2>
  35. <h2>学生年龄:{{age}}</h2>
  36. </div>
  37. `,
  38. data() {
  39. return {
  40. studentName: '张三',
  41. age: 18
  42. }
  43. }
  44. });
  45. new Vue({
  46. el: '#app',
  47. components: {
  48. 'school-component': school, // 此处的定义的属性名才是真正的组件名,上面定义组件时的变量名只是一个临时的中转变量名
  49. 'student-component': student
  50. }
  51. });
  52. </script>

注册全局组件:

  1. <body>
  2. <div id="app">
  3. <hello></hello>
  4. </div>
  5. </body>
  6. <script>
  7. const hello = Vue.extend({
  8. template:
  9. `
  10. <div>
  11. <h2>{{msg}}</h2>
  12. </div>`,
  13. data() {
  14. return {
  15. msg: 'hello'
  16. }
  17. }
  18. });
  19. // 将组件注册为全局组件
  20. // 参数1:组件名
  21. // 参数2:组件
  22. Vue.component('hello', hello);
  23. new Vue({
  24. el: '#app'
  25. }
  26. </script>

组件名注意点:

组件名为一个单词时:可以全小写,也可以首字母大写(推荐)

  1. new Vue({
  2. el: '#app',
  3. components: {
  4. Student: student // 单个单词时,可以首字母大写,也可以全小写
  5. }
  6. });

组件名为多个单词组成时:使用短横连接

  1. new Vue({
  2. el: '#app',
  3. components: {
  4. 'my-student': student // 多个单词时,使用短横连接
  5. }
  6. });

如果是脚手架环境,可以使用所有单词首字母都大写的形式(推荐):

  1. new Vue({
  2. el: '#app',
  3. components: {
  4. MyStudent: student // 多个单词时,所有单词首字母都大写。(需要是脚手架环境才可以,引用vue.js是不可以处理首字母大写的)
  5. }
  6. });

组件名尽可能回避html中已经有的元素名称,例如:h2、H2等都不可以。

可以使用name配置项指定组件在开发者工具中呈现的名字。例如:

  1. <body>
  2. <div id="app">
  3. <student-component></student-component>
  4. <hr>
  5. </div>
  6. </body>
  7. <script>
  8. Vue.config.productionTip = false;
  9. const student = Vue.extend({
  10. // 使用name属性配置该组件在Vue开发者工具中显示的名称。该名称不会影响组件在new Vue注册的名字。
  11. name:'test',
  12. template:
  13. `
  14. <div>
  15. <h2>学生姓名:{{studentName}}</h2>
  16. <h2>学生年龄:{{age}}</h2>
  17. </div>
  18. `,
  19. data() {
  20. return {
  21. studentName: '张三',
  22. age: 18
  23. }
  24. }
  25. });
  26. new Vue({
  27. el: '#app',
  28. components: {
  29. 'student-component': student
  30. }
  31. });
  32. </script>

组件标签的写法:

  1. <!-- 第一种写法:正常的双标签 -->
  2. <school></school>
  3. <!-- 第二种写法:自闭合 -->
  4. <school />

第二种写法需要在脚手架环境下使用。如果不是脚手架环境,<school/>会导致后续组件不能正确渲染。

组件配置的简写形式:

  1. const school = Vue.extend(options);
  2. // 可以简写为:
  3. const school = options;

组件嵌套

组件可以嵌套使用,在父组件里嵌套子组件。

例如:

  1. <body>
  2. <div id="app">
  3. <school></school>
  4. </div>
  5. </body>
  6. <script>
  7. Vue.config.productionTip = false;
  8. const student = {
  9. template:
  10. `<div>
  11. <h2>{{studentName}}</h2>
  12. </div>`,
  13. data() {
  14. return {
  15. studentName: 'tom'
  16. }
  17. }
  18. }
  19. // school内部嵌套student组件
  20. const school = {
  21. template:
  22. `<div>
  23. <h2>{{schoolName}}</h2>
  24. <student></student>
  25. </div>`,
  26. data() {
  27. return {
  28. schoolName: '庞各庄小学'
  29. }
  30. },
  31. components: {
  32. student
  33. }
  34. }
  35. new Vue({
  36. el: '#app',
  37. components: {
  38. school
  39. }
  40. })
  41. </script>

实际开发中,一般在vm中只有一个叫app的组件,其他组件都嵌套进app组件内。

例如:

  1. <body>
  2. <div id="app">
  3. </div>
  4. </body>
  5. <script>
  6. Vue.config.productionTip = false;
  7. const student = {
  8. template:
  9. `<div>
  10. <h2>{{studentName}}</h2>
  11. </div>`,
  12. data() {
  13. return {
  14. studentName: 'tom'
  15. }
  16. }
  17. }
  18. const school = {
  19. template:
  20. `<div>
  21. <h2>{{schoolName}}</h2>
  22. <student></student>
  23. </div>`,
  24. data() {
  25. return {
  26. schoolName: '庞各庄小学'
  27. }
  28. },
  29. components: {
  30. student
  31. }
  32. }
  33. const hello = {
  34. template:
  35. `<div>
  36. <h2>{{msg}}</h2>
  37. </div>`,
  38. data() {
  39. return {
  40. msg: 'hello'
  41. }
  42. }
  43. }
  44. // 其他组件位于app组件下
  45. const app = {
  46. template:
  47. `<div>
  48. <hello></hello>
  49. <school></school>
  50. </div>`,
  51. components: {
  52. hello,
  53. school
  54. }
  55. }
  56. // vm中只管理app一个组件
  57. new Vue({
  58. el: '#app',
  59. template:`<app></app>`,
  60. components: {
  61. app
  62. }
  63. })
  64. </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__属性,该属性称为隐式原型属性。

显示原型属性、隐式原型属性都指向了同一个对象,叫做原型对象。

对象的隐式原型属性(原型对象)指向自己的缔造者。

  1. // 定义一个构造函数
  2. function Demo() {
  3. this.a = 1;
  4. this.b = 2;
  5. }
  6. // 创建一个Demo的实例对象
  7. const d = new Demo();
  8. console.log(Demo.prototype); // 显示原型属性
  9. console.log(d.__proto__); // 隐式原型属性
  10. console.log(Demo.prototype === d.__proto__); // true,这两个属性都指向了同一个对象,叫做原型对象

因为Demo.prototyped.__proto__是同一个对象,所以操作Demo.prototype时实例对象也会变:

  1. Demo.prototype.x = 99;
  2. console.log('d.__proto__.x:' + d.__proto__.x); // d.__proto__.x 也可以输出99

进一步的,如果程序中使用了d.x,而d对象本身没有x属性,就会顺着原型链查找到d.__proto__.x

  1. console.log('d.x:' + d.x); // d.x 也可以输出99。 d本身没有x属性,但是js会通过原型链d.__proto__找到d.__proto__.x

Vue组件中的内置关系

Vue组件中:Vue组件的原型对象的原型对象,就是Vue的原型对象

  1. VueComponent.prototype.__proto__ === Vue.prototype

单文件组件

一个文件就是一个组件,组件的模板、样式、定义都在该文件中。

文件名后缀为.vue,里面可以编写3个标签:

  1. <template>
  2. <!-- 组件的结构,即配置的组件模板 -->
  3. </template>
  4. <script>
  5. // 组件交互相关的代码(数据、方法等)
  6. </script>
  7. <style>
  8. /* 组件的样式 */
  9. </style>

推荐为VSCode安装 Vetur插件进行VUE代码的编写。

示例:

  1. <template>
  2. <!-- 组件模板 -->
  3. <div class="demo">
  4. <h2>{{studentName}}</h2>
  5. </div>
  6. </template>
  7. <script>
  8. // 定义组件
  9. const school = Vue.extend({
  10. name: 'School', // vue开发者工具中显示的名称
  11. data() {
  12. return{
  13. studentName: 'tom'
  14. }
  15. }
  16. });
  17. // 将组件暴露出去。也可以使用其他export方式,推荐使用 export default 进行暴露
  18. export default School;
  19. </script>
  20. <style>
  21. .demo{
  22. background-color: skyblue;
  23. }
  24. </style>

定义组件的位置一般使用简写:

  1. <script>
  2. // 简写形式:
  3. // 不再定义临时的中转变量,直接在定义时就export出去
  4. // 不再使用Vue.extend,使用简写形式直接编写options
  5. export default {
  6. name: 'School',
  7. data() {
  8. return{
  9. studentName: 'tom'
  10. }
  11. }
  12. }
  13. </script>

实际开发中,会创建一个App组件管理其他组件:

  1. <template>
  2. <div>
  3. <school />
  4. <student />
  5. </div>
  6. </template>
  7. <script>
  8. import School from './School'
  9. import Student from './Student.vue'
  10. export default {
  11. name: 'App',
  12. components: {School,Student}
  13. }
  14. </script>
  15. <style>
  16. </style>

另外,会创建一个main.js作为入口文件,用来创建vm实例:

  1. import App from './App'
  2. new Vue({
  3. el: '#root',
  4. template: `<app/>`,
  5. comments: { App }
  6. })

最后在页面中引入main.js

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>首页</title>
  5. </head>
  6. <body>
  7. <div id="root"></div>
  8. <script src="./scripts/vue.js"></script>
  9. <!-- 最好在body最下方引入main.js,此时页面已经加载 -->
  10. <script src="./main.js"></script>
  11. </body>
  12. </html>

HTML的其他标签

html中的<head>标签中,出现的<meta>的含义:

  1. <head>
  2. <!-- 编码 -->
  3. <meta charset="UTF-8">
  4. <!-- 针对IE浏览器的一个特殊配置,含义是让IE浏览器以最高的渲染级别渲染页面 -->
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <!-- 开启移动端的理想视口 -->
  7. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  8. </head>

html中的<noscript>标签,如果浏览器不支持js则会渲染出来:

  1. <body>
  2. <noscript>
  3. 不好意思,您的浏览器不支持js。
  4. </noscript>
  5. </body>