Vue_2 --- 组件化编程

1. 模块与组件

1.1 模块化编写应用

向外提供特定功能的js程序,一般就是一个js文件,也就是一个模块

存在的问题

  1. 依赖关系混乱,不好维护
  2. 代码复用率不高

1.2 组件化编写引用

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

优点

  1. 好维护
  2. 代码复用率高

2. 非单文件组件

一个文件中包含多个组件

1. 创建组件(局部注册)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <h1>{{msg}}</h1>
    <!-- 4. 使用 school 组件 -->
    <School></School>
    <hr>
    <!-- 4. 使用 student 组件,两个单词组成的需要用 - 连接 -->
    <student-msg></student-msg>
    <!-- 可以用自闭合标签,但是要再vue脚手架中使用 -->
    <student-msg/>
</div>

</body>
<script>
    Vue.config.productionTip = false

    // 1. 创建组件
    // 创建 school 组件,组件名首字母大写
    const School = Vue.extend({
        // el:"#root",  // 组件定义时,一定不要写el配置项,因为最终所有的组件爱你都要被vm管理,由vm决定服务于哪个容器节点
        // 定义组件内的模板
        name:"School",  // 可以定义组件在开发者工具中的名字
        template: `
          <div>
            <h1>学校名称: {{ schoolName }}</h1>
            <h1>学校地址: {{ address }}</h1>
          </div>
        `,
        data() { // 组件中的data定义为函数形式,是为了不会当其中一个组件修改了data中的数据从而影响其他组件中的数据,因为data()返回的都是一个新的对象
            return {
                schoolName: "实验中学",
                address: "北京",
            }
        }
    })

    // 创建 student 组件,组件名首字母大写
    const StudentMsg = Vue.extend({
        // el:"#root",  // 组件定义时,一定不要写el配置项,因为最终所有的组件爱你都要被vm管理,由vm决定服务于哪个容器节点
        // 定义组件内的模板
        template: `
          <div>
            <h1>学生名称: {{ studentName }}</h1>
            <h1>学生年龄: {{ age }}</h1>
          </div>
        `,
        data() { // 组件中的data定义为函数形式,是为了不会当其中一个组件修改了data中的数据从而影响其他组件中的数据,因为data()返回的都是一个新的对象
            return {
                studentName: "张三",
                age: 18
            }
        }
    })

    // 2. 创建Vue对象
    new Vue({
        el: '#app',
        data: {
            msg: "Vue实例"
        },
        // 3. 注册组件(局部注册)
        components: {
            School,
            StudentMsg
        }
    })

</script>
</html>

定义组件的简写方式

<script>
    // 内部会有判断,如果是对象,会自动调用 Vue.extend()
	const StudentMsg = {
        // el:"#root",  // 组件定义时,一定不要写el配置项,因为最终所有的组件爱你都要被vm管理,由vm决定服务于哪个容器节点
        // 定义组件内的模板
        template: `
          <div>
            <h1>学生名称: {{ studentName }}</h1>
            <h1>学生年龄: {{ age }}</h1>
          </div>
        `,
        data() { // 组件中的data定义为函数形式,是为了不会当其中一个组件修改了data中的数据从而影响其他组件中的数据,因为data()返回的都是一个新的对象
            return {
                studentName: "张三",
                age: 18
            }
        }
    }
</script>

2. 创建组件(全局注册)

<script>
    Vue.config.productionTip = false
    
    // 创建 School组件
     const School = Vue.extend({
        template: `
          <div>
            <h1>学校名称: {{ schoolName }}</h1>
            <h1>学校地址: {{ address }}</h1>
          </div>
        `,
        data() { 
            return {
                schoolName: "实验中学",
                address: "北京",
            }
        }
    })
    
    // 注册组件(全局注册)
	Vue.component("School",school)
    
    new Vue({
        el: '#app',
    })

</script>

3. 组件嵌套

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <h1>{{msg}}</h1>
    <!-- 4. 使用 school 组件 -->
    <School></School>
    <hr>
    <!-- 4. 使用 student 组件 -->
</div>

</body>
<script>
    Vue.config.productionTip = false

    // 1. 创建组件

    // 创建 student 组件
    const StudentMsg = Vue.extend({
        template: `
          <div>
            <h1>学生名称: {{ studentName }}</h1>
            <h1>学生年龄: {{ age }}</h1>
          </div>
        `,
        data() {
            return {
                studentName: "张三",
                age: 18
            }
        }
    })

    // 创建 school 组件,并在其中嵌套 student 组件
    const School = Vue.extend({
        template: `
          <div>
            <h1>学校名称: {{ schoolName }}</h1>
            <h1>学校地址: {{ address }}</h1>
            <student-msg></student-msg>   <!-- school 组件中 写 student 组件的标签 -->
          </div>
        `,
        data() {
            return {
                schoolName: "实验中学",
                address: "北京",
            }
        },
        // 在 school 组件中注册 student 组件
        components: {
            StudentMsg
        }
    })


    // 2. 创建Vue对象
    new Vue({
        el: '#app',
        // 3. 注册组件(局部注册)
        components: {
            School,
        }
    })

</script>
</html>

4. 组件标准化开发

以后标准化开发过程中,会由 vm 只管理 一个 app 这个顶层组件, app中再管理着多个子组件和子嵌套组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
</head>
<body>
<!-- 空容器,由vm将app组件放到容器 -->
<div id="app">
</div>

</body>
<script>
    Vue.config.productionTip = false

    // 1. 创建组件

    // 创建 student 组件
    const StudentMsg = Vue.extend({
        template: `
          <div>
            <h1>学生名称: {{ studentName }}</h1>
            <h1>学生年龄: {{ age }}</h1>
          </div>
        `,
        data() {
            return {
                studentName: "张三",
                age: 18
            }
        }
    })

    // 创建 school 组件,并在其中嵌套 student 组件
    const School = Vue.extend({
        template: `
          <div>
            <h1>学校名称: {{ schoolName }}</h1>
            <h1>学校地址: {{ address }}</h1>
            <student-msg></student-msg>   <!-- school 组件中 写 student 组件的标签 -->
          </div>
        `,
        data() {
            return {
                schoolName: "实验中学",
                address: "北京",
            }
        },
        // 在 school 组件中注册 student 组件
        components: {
            StudentMsg
        }
    })

    // 创建app组件
    const app = Vue.extend({
        template: `<school></school>`,
        components: {
            School,
        }
    })


    // 2. 创建Vue对象
    new Vue({
        el: '#app',
        template: `<app></app>`,
        // 3. 注册 app 组件(局部注册)
        components: {
            app,
        }
    })

</script>
</html>

5. VueComponent --- 组件实例对象

  1. 组件的本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend()生成的
  2. 我们只需要写<school/><school></school>,Vue解析模板时会帮我们创建组件的实例对象,即Vue执行的: new VueComponent(options)
  3. 特别注意: 每次调用Vue.extend(),返回的都是一个全新的 VueComponent 实例对象
  4. 关于this指向:
    1. 组件的{}对象配置中:data函数,methods中的函数,watch中的函数,computed中的函数,他们的this均是VueComponent 实例对象
    2. new Vue(options) 中的options配置中的:data函数,methods中的函数,watch中的函数,computed中的函数,他们的this均是Vue 实例对象
  5. VueComponent 的实例对象,简称vc,Vue 的实例对象,简称 vm,vc 和vm 的功能差不多,也有数据监视和数据代理,vm实例中的$children是个数组,存储着一个一个的vc,每个vc的$children也是个数组,存储着一个一个的嵌套组件vc,但是vc不能写el配置项,data必须写成函数形式return一个对象

6. 内置关系

1. 原型对象的概述(类继承)

// 定义一个构造函数
function Demo(){
    this.a = 1
    this.b = 2
}

// 创建一个实例
const d = new Demo()

console.log(Demo.prototype)    // 显式原型属性
console.log(d.__proto__)      // 隐式原型属性

// 它们两个所指向的都是同一个对象: 原型对象

// 程序员通过显式原型属性操作原型对象,设置一个属性x,值是99
Demo.prototype.x = 99

// 调用d.x时,d身上没有x这个属性,自动顺着隐式原型属性找原型对象身上有没有x属性
console.log(d.x)   // 其本质是 d.__proto__.x  通过隐式原型属性调用x,可以省略

2. 对象的指向关系

3. 结论

  1. 内置关系: VueComponent.prototype.__proto__ === Vue.prototype
  2. 为什么要有这个关系: 让组件实例对象(vc)可以访问到Vue原型上的属性、方法

3. 单文件组件(常用)

一个文件中只包含一个组件,以.vue结尾的文件

1. 文件结构

<template>  <!-- template 标签是不参与编译的,即最终呈现在浏览器中的结构不会出现template这个标签 -->
  <!-- 组件的标签结构 -->
</template>

<script>
// 组件交互相关的代码(数据,方法)
</script>

<style>
/* 组件的样式 */
</style>

2. 对外暴露方式

1. 分别暴露

<template>
  <div class="demo">
    <h1>学校名称: {{ name }}</h1>
    <h1>学校地址: {{ address }}</h1>
  </div>
</template>

<script>
// 对外暴露组件的方式一: 分别暴露
export const school = {
  name: "School",  
  data() {
    return {
      name: "实验中学",
      address: "北京",
    }
  }
}
</script>

<style>
.demo {

}
</style>

外部的引用方式

import {school} from "文件路径"

2. 统一暴露

<template>
  <div class="demo">
    <h1>学校名称: {{ name }}</h1>
    <h1>学校地址: {{ address }}</h1>
  </div>
</template>

<script>
const school = {
  name: "School",
  data() {
    return {
      name: "实验中学",
      address: "北京",
    }
  }
}
// 对外暴露组件的方式一: 统一暴露
export {school}
</script>

<style>
.demo {

}
</style>

外部的引用方式

import {school} from "文件路径"

3. 默认暴露(常用)

<template>
  <div class="demo">
    <h1>学校名称: {{ name }}</h1>
    <h1>学校地址: {{ address }}</h1>
  </div>
</template>

<script>

export default {
  name: "School",
  data() {
    return {
      name: "实验中学",
      address: "北京",
    }
  }
}

// 对外暴露组件的方式三: 默认暴露
</script>

<style>
/* 组件的样式 */
.demo {

}
</style>

外部的引用方式

import school from "文件路径"

3. 目录结构

1. School 组件

<template>
  <div class="demo">
    <h1>学校名称: {{ name }}</h1>
    <h1>学校地址: {{ address }}</h1>
  </div>
</template>

<script>

export default {
  name: "School",
  data() {
    return {
      name: "实验中学",
      address: "北京",
    }
  }
}

// 对外暴露组件的方式三: 默认暴露
</script>

<style>
/* 组件的样式 */
.demo {

}
</style>

2. App.vue

<template>
  <!-- 2. 使用组件 -->
  <div>
    <School/>
  </div>
</template>

<script>
// 1. 引入组件
import School from "./School.vue";

export default {
  name: "App",
  components: {School},
  data() {
    return {}
  }
}
</script>

<style>

</style>

3. main.js

import App from "./App.vue";

new Vue({
    el: "#root",
    template: `<App/>`,   // 将 App 组件放入root 的模板中
    components: {App}
})

4. index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>单文件组件</title>
</head>
<body>
<!-- 1. 创建容器 -->
<div id="root"></div>
<!-- 2. 引入 vue.js -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<!-- 3. 引入 main.js  -->
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
posted @ 2024-03-13 21:08  河图s  阅读(14)  评论(0)    收藏  举报