11.Vue - 组件——组件名、非单文件组件、单文件组件

本文详细介绍了Vue中的组件化思想,包括非单文件组件的创建、使用步骤、组件嵌套和VueComponent的本质。内容涵盖组件的定义、数据处理、注册方式以及组件间的内在关系。此外,还探讨了el定义、data函数问题和组件注册的两种方式。最后,对非单文件组件进行了总结,并简要提及了单文件组件的概念。
摘要由CSDN通过智能技术生成

目录

一、 组件

1.1 了解组件

1.2 非单文件组件

1.2.1 使用步骤

1.2.2 效果图

1.3 组件嵌套

1.4 VueComponent

二、 非单文件组件总结

2.1 el 定义问题

2.2 data函数问题

2.3 注册组件方式

2.4 内置关系

2.4.1 铺垫知识

2.4.2 内置关系

2.5 总结

三、单文件组件


一、 组件

1.1 了解组件

传统方式编写应用

image-20231113142708958

组件方式编写应用

image-20231113143317337

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

所有的组件都必须听大哥vm的指挥,并且组件可以产生嵌套

组件可以复用编码,简化项目编码,提高运行效率

image-20231113143528818

模块:一个模块也就是一个JS文件

模块化后可以复用JS,简化JS的编写,提高JS运行效率

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

一个JS文件太大,我们可以拆分成许多份,也就是模块化应用

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

一个组件太大,可以按照功能点拆成许多份,不同的功能点就是一个组件,这样就是一个组件化

Vue中组件有两种形式

  • 非单文件组件

    一个文件中包含n个组件

  • 单文件组件

    一个文件中只包含1个组件。文件名是a.vue而不是a.html,后缀名称发生了改变

1.2 非单文件组件

将下面的形式改成非单文件组件

    <!--准备好一个容器-->
    <div id="root">
        <h2>学校名称:{{schoolName}}</h2>
        <h2>学校地址:{{address}}</h2>
        <hr>
​
        <h2>学生姓名:{{studentName}}</h2>
        <h2>学生年龄:{{age}}</h2>
    </div>

data: {
       schoolName:'qilugongyedaxue',
       address:'济南',
       studentName:'zhangjingqi',
       age:18
}

image-20231113145855091

1.2.1 使用步骤

我们可以将学校信息创建为一个组件,将学生信息创建为一个组件

  1. 创建组件

    template是一个模板字符串,在使用template需要有一个根元素,我们一般设置为div标签

    
//创建school组件
    //Vue.extent扩展,创建组件的API
    //这个school不是组件名,只是一个中转的变量
    const school = Vue.extend({
        // 用div包裹,但是这个div最终不会出现在页面上
        template: `<div>
                   <h2>学校名称:{{schoolName}}</h2>
                   <h2>学校地址:{{address}}</h2>
                   <button @click="showName">点我提示学校名称</button>
                     </div> `
        ,
        data() {
​
            return {
                schoolName: 'qiludongyedaxue',
                address: '济南',
            }
        },
        methods: {
            showName() {
                alert(this.schoolName)
            }
        },
    })
​
    // 创建student组件
    //这个student不是组件名,只是一个中转的变量
    const student = Vue.extend({
        template: `<div>
                         <h2>学生姓名:{{studentName}}</h2>
                         <h2>学生年龄:{{age}}</h2>
                      </div> `
        ,
        data() {
            return {
                studentName: '张三',
                age: 18
            }
        }
    })

  1. 局部注册组件

     
 new Vue({
            el:'#root',
            // 这个地方依然可以写数据,依然可以用
            data:{
 
            },
            // 注册组件(局部注册)
            components:{
                // 这个地方是key:value的形式,key是组件的名字 value就是我们上面定义的const,我们上面创建的const不是组件名,是我们中转的变量,下面的key才是组件名
                // school:school,
                // student:student
                // 下面是简写
                school,
                student
            }
     )}

  1. 编写组件标签

 <body>
        <div id="root">
        <!--第三步:编写组件标签  -->
        <school></school>
          <br><br>
        <student></student>
        </div>
</body>

我们代码中组件标签开头字母是小写,但是在Vue开发工具中是大写的

image-20231113154144015

1.2.2 效果图

image-20231113153622616

完整代码

<!DOCTYPE html>
​
<html>
​
<head>
    <meta charset="UTF8" />
    <title>初始vue</title>
​
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
​
</head>
​
<body>
    <div id="root">
        <!--第三步:编写组件标签  -->
        <school></school>
        <br><br>
        <student></student>
    </div>
</body>
<script type="text/javascript">
    //关闭开发环境时的生产提示
    Vue.config.productionTip = false
​
​
    //创建school组件
    //Vue.extent扩展,创建组件的API
    const school = Vue.extend({
        // 用div包裹,但是这个div最终不会出现在页面上
        template: `<div>
                   <h2>学校名称:{{schoolName}}</h2>
                   <h2>学校地址:{{address}}</h2>
                   <button @click="showName">点我提示学校名称</button>
                     </div> `
        ,
        //el:'#root',   如果存在此语句的话,也会报错
​
        // 如果data写成这种形式会报错,只能写成函数的形式
        // data:{
        //   schoolName:'qiludongyedaxue',
        //   address:'济南',
        // },
​
        data() {
​
            return {
                schoolName: 'qiludongyedaxue',
                address: '济南',
            }
        },
        methods: {
            showName() {
                alert(this.schoolName)
            }
        },
    })
​
​
    // 创建student组件
    const student = Vue.extend({
        template: `<div>
                         <h2>学生姓名:{{studentName}}</h2>
                         <h2>学生年龄:{{age}}</h2>
                      </div> `
        ,
        data() {
            return {
                studentName: '张三',
                age: 18
            }
        }
    })
​
​
    new Vue({
        el: "#root",
        //这里面继续写配置也可以
        data: {
        },
        components: {
            // 这个地方是key:value的形式,key是组件的名字 value就是我们上面定义的const,我们上面创建的const不是组件名,是我们中转的变量,下面的key才是组件名
            // school:school,
            // student:student
            // 下面是简写
            school,
            student
        }
    })
</script>
​
</html>

1.3 组件嵌套

在下图中,蓝色框和和橙色框中的组件就是嵌套,蓝色框组件嵌套了两个橙色框组件,并且有一个上下级关系

蓝色框称为父组件

橙色框称为子组件

image-20231113163417597

下面完成school组件嵌套student组件

也就是父组件school,子组件student

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title> 初识vue</title>
        <!--引入vue    引入之后,全局就多了一个vue这个构造函数-->
        <script type="text/javascript" src="../js/vue.js"></script> 
    </head>
    <body>
        <div id="root">
             <app></app>
        </div>
 
    </body>
    
    <script type="text/javascript">
        //阻止vue在启动时生成生产提示
        Vue.config.productionTip=false
 
        // 创建student组件
        const student = Vue.extend({
            template:`<div>
                         <h2>学生姓名:{{studentName}}</h2>
                         <h2>学生年龄:{{age}}</h2>
                      </div> `
            ,
            data(){
              return{
                studentName:'张三',
                age:18
              }
            }
        })
 
        // 创建school组件
        const school = Vue.extend({
            // 用div包裹,但是这个div最终不会出现在页面上
            // 嵌套了student组件
            template:`<div>
                   <h2>学校名称:{{schoolName}}</h2>
                   <h2>学校地址:{{address}}</h2>
                   <student></student>
                     </div> `
            ,
            data(){
                
                return{
                 schoolName:'qilugongyedaxue',
                 address:'济南',
                }
            },
            components:{
                // 注意!这里嵌套的时候有一个先后关系,一定要先创建student组件
                student
            }
        })
 
        // 创建hello组件
        const hello =Vue.extend({
            template:`<h1>{{msg}}</h1>`,
            data(){
                return {
                    msg:'欢迎来到qilugongyedaxue学习'
                }
            }
        })
 
        // 创建app组件  其他的组件都在这个地方
        // 一人之下,万人之上(在vm下)
        const app = Vue.extend({
            template:  `
                        <div>
                             <hello></hello>
                             <school></school>
                         </div>    `
 
            ,
            components:{
                //school组件中嵌套了student组件
                school,
                hello,
            }
        })
 
 
        new Vue({
            el:'#root',
            //注册组件
            components:{
               app
            }
 
        })
 
    </script>   
</html>

我们上面定义的模式是vm组件管理app组件,然后app组件管理其他相关组件

image-20231113164515909

1.4 VueComponent

我们可以输出一下定义的组件

const school = Vue.extend({
            // 用div包裹,但是这个div最终不会出现在页面上
            // 嵌套了student组件
            template:`<div>
                   <h2>学校名称:{{schoolName}}</h2>
                   <h2>学校地址:{{address}}</h2>
                   <student></student>
                     </div> `
            ,
            data(){
                
                return{
                 schoolName:'qilugongyedaxue',
                 address:'济南',
                }
            },
            components:{
                // 注意!这里嵌套的时候有一个先后关系,一定要先创建student组件
                student
            }
        })
​
console.log('@',school)

发现是一个构造函数,组件的本质就是一个构造函数

image-20231113165424334

  1. school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的

    image-20231113165740463

  2. 我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象

    即Vue帮我们执行的:new VueComponent(options)

  3. 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!

school与hello是两个VueComponent,只不过两个长得一样,功能也一样

img

下面验证即可

console.log('@',school === hello)

image-20231113170354588

或者是通过下面的原码,每次创建组件的时候都是重新定义的一个变量Sub

image-20231113170630511

  1. 关于this的指向

  • 组件配置中

    data函数、methods中的函数、watch中的函数、computed中的函数,this指向的均是vc实例对象

  • new Vue配置中

    data函数、methods中的函数、watch中的函数、computed中的函数,this指向均是vm实例对象

vc和vm 的功能是一个样子的,也有数据代理

image-20231113171408061

  1. VueComponent的实例对象,以后简称vc,也可称为组件实例对象

组件是可复用的Vue实例,所以它们与new Vue 接收相同的选项,例如data、computed、watch、methods以及声明周期钩子等。

仅有的例外是像el这样跟实例特有的选项

vm能通过el决定为哪个容器进行服务,vc不能

二、 非单文件组件总结

2.1 el 定义问题

我们在使用Vue.extent创建组件的时候编写了el:'#root',这种情况是会报错的,

提示el仅仅被使用在实例身上并且使用new关键字调用的时候

    
const school = Vue.extent({
            // 用div包裹,但是这个div最终不会出现在页面上
            template:`<div>
                   <h2>学校名称:{{schoolName}}</h2>
                   <h2>学校地址:{{address}}</h2>
                   <button @click="showName">点我提示学校名称</button>
                     </div> `
            ,
            el:'#root',   //如果存在此语句的话,也会报错
        
            // 如果data写成这种形式会报错,只能写成函数的形式
            data:{
               schoolName:'qilugongyedaxue',
               address:'济南',
            }
  )}

image-20231113150828713

那我们不写el指定根容器,那怎么知道为谁服务

因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器

创建组件的时候从来不说组件为谁服务,组件就是一块砖,哪里需要往哪搬,最终为谁服务看大哥vm的指示

2.2 data函数问题

假如我们在非单文件组件中如下所示定义data,就会报错

data:{
    schoolName:'qilugongyedaxue',
    address:'济南',
}

image-20231113151444643

data(){
   return{
       schoolName:'qilugongyedaxue',
       address:'济南',
   }
}

为什么非要写成一个函数

是因为对象的引用关系。假如A组件和B组件同时引用了school组件,然后A组件中对schoolName进行修改,那B组件中引用的schoolName也会跟着修改,可能会导致B组件页面渲染发生问题

但是写成一个函数的形式,A组件和B组件之间修改就不会互相影响了。因为我们每次调用data的时候都是返回一个全新的对象

2.3 注册组件方式

组件的注册分为局部注册和全局注册

  • 局部注册

    这种方式使用的较多

   
 // 创建student组件
    const student = Vue.extend({
        template: `<div>
                         <h2>学生姓名:{{studentName}}</h2>
                         <h2>学生年龄:{{age}}</h2>
                      </div> `
        ,
        data() {
            return {
                studentName: '张三',
                age: 18
            }
        }
    })
​
    new Vue({
        el: "#root",
        //这里面继续写配置也可以
        data: {
        },
        components: {
            school,
            student
        }
    })

  • 全局注册

//1.创建hello组件
const student = Vue.extend({....})
​
//2.全局注册组件
// 参数1:组件的名字;
// 参数2:传入我们定义的组件
Vue.component('hello',hello)

2.4 内置关系

2.4.1 铺垫知识

无论是函数身上的显示原型属性还是实例对象身上的隐式原型属性,都指向原型对象

//定义一个构造函数
function Demo(){
   this.a = 1
   this.b = 2
}
​
// 创建一个Demo实例对象
const d = new Demo()
​
//Demo.prototype显示原型属性
// 我们通过Demo.prototype已经拿到原型对象了
console.log(Demo.prototype)
​
//此构造函数所缔造出来的实例对象有一个__proto__属性(前后两个下划线)
//隐式原型属性
console.log(d.__proto__)

程序员通过显示原型属性操作原型对象,追加一个x属性,值为99

//拿到原型对象后往其身上加了一个x属性为99
Demo.prototype.x=99

访问刚刚添加的x属性值

console.log(d.x)
//两种方式都可以 
console.log(d.__proto__.x)

Demo自身没有x,就会去隐式里面找,就会找到x

image-20231113204813939

并且下面的结果其实是true

console.log(d.__proto__ === Demo.prototype)

2.4.2 内置关系

VueComponent.prototype.__proto__===Vue.prototype

可以使用下面的代码验证一下我们的结论

<script type="text/javascript">
    //关闭开发环境时的生产提示
    Vue.config.productionTip = false


    //定义组件VueComponent
    const school = Vue.extend({
        // 用div包裹,但是这个div最终不会出现在页面上
        // 嵌套了student组件
        template: `<div>
                   <h2>学校名称:{{schoolName}}</h2>
                   <h2>学校地址:{{address}}</h2>
                     </div> `
        ,
        data() {

            return {
                schoolName: 'qilugongyedaxue',
                address: '济南',
            }
        }
    })

    console.log(school.prototype.__proto__ === Vue.prototype)//true

    new Vue({
        el: "#root",
        data: {
            msg: '你好'
        }
    })
</script>

下面分析Vue与VueComponent的关系

  1. 当我们使用下面语句后,Vue实例引入进来

<script type="text/javascript" src="../js/vue.js"></script>

Vue构造函数就位,config、component....是Vue身上的属性和方法

image-20231113211005384

  1. Vue身上还有一个prototype属性

    Vue的原型对象

image-20231113211152476

之前在学习el两种写法的时候见过$mount函数

其实vm身上是没有$mount函数的,但是顺着隐式原型链__proto__就可以找到$mount函数

vm.$mount('#root')

  1. new Vue可以创建Vue原型对象,创建的vm实例一定会有一个隐式原型对象__proto__

image-20231113211710515

  1. Vue的原型对象也会有隐式原型属性,并且指向Object的原型对象

    实例的原型属性永远指向自己缔造者的原型对象

    Vue原型对象的缔造者是Object原型对象

    Vue的实例对象的缔造者是Vue的原型对象

image-20231113211849760

  1. 同理VueComponent函数身上也会有一个prototype,并且指向VueComponent的原型对象

image-20231113213346068

  1. 假如编写了一个组件标签<school/>,随后Vue就帮我们new了一个VueComponent的实例对象vc

image-20231113213511715

  1. vc也是一个实例对象,身上也会有隐式原型属性,并且指向自己的缔造者的原型对象,即指向VueComponent的原型对象

image-20231113213649134

  1. 同理VueComponent的原型对象也会有隐式原型属性,并且指向自己缔造者的原型对象,但是Vue做了一件事,没有让VueComponent的原型对象的隐式原型属性指向Object的原型对象,而是让VueComponent的原型对象的隐式原型属性指向Vue的原型对象

image-20231113214451240

  1. 图示总览

    总的来说就是,VueComponent的原型对象的原型对象就是Vue的原型对象

img

为什么要这么折腾一圈呢

当放在Vue的原型对象一个属性x=99,那vc首先会在自己实例对象身上找,找不到的话就会在隐式原型对象上找,也就是VueComponent的原型对象

继续在VueComponent的原型对象上找,如果找不到的话会在隐式原型对象上找,也就是Vue原型对象,最终找到了

假如说在Vue原型对象上也没有找到,会继续在Object原型对象身上找

image-20231113214927315

2.5 总结

  • Vue中使用组件步骤

  1. 定义组件(创建组件)

  2. 注册组件

  3. 使用组件(写组件标签)


  • 如何定义一个组件

使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有差别

区别

  1. el不写。最终所有的组件都要经过一个vm管理,由vm中的el决定服务哪个容器

  2. data必须写成函数。避免组件被复用时,数据存在引用关系(比如a,b同时用了data数据,a改了数据,那b得到的数据就是a改了之后的数据)

备注:使用template可以配置组件结构


  • 关于组件标签

第一种写法:<school></school>

第二种写法:<school/>

备注:

不使用脚手架时,<school/>会导致后续组建不能渲染


  • 关于组件名

一个单词组成

第一种写法(首字母小写):school

第二种写法(首字母大写):School

多个单词组成

第一种写法(kebab-case命名):my-school

第二种写法(CamelCase命名):MySchool(需要Vue脚手架支持)

备注

1. 组件名尽可能回避HTML中已有的元素名称,例如:h2,H2都不可以

2. 可以使用name配置项指定组件在开发者工具中呈现的名字,如下所示

给组件添加一个name配置项即可,其他地方都不改变

    <div id="root">
        <!--第三步:编写组件标签  -->
        <school></school>
        <br><br>
        <student></student>
    </div>

   // 创建student组件
    const student = Vue.extend({
        name:'zhangjignqi',
        template: `<div>
                         <h2>学生姓名:{{studentName}}</h2>
                         <h2>学生年龄:{{age}}</h2>
                      </div> `
        ,
        data() {
            return {
                studentName: '张三',
                age: 18
            }
        }
    }),
​
        new Vue({
        el: "#root",
        data: {
'22'
            // }
        },
        components: {
            school,
            student
        }
    })

image-20231113161250781


  • 注册组件的简写方式

const school =Vue.extend(options)

可以简写为下面所示代码:

直接编写配置对象

const school = options

三、单文件组件

单文件组件的后缀是.vue文件

但是怎么编译怎么运行,需要学习脚手架

创建文件的命名可以参考2.5总结中的内容

一个单词组成

第一种写法(首字母小写):school.vue

第二种写法(首字母大写):School.vue

多个单词组成

第一种写法(kebab-case命名):my-school.vue

第二种写法(CamelCase命名):MySchool.vue(需要Vue脚手架支持)

一般页面的编写需要html、css、js,Vue为了完成这些常见的属性,提供了一些标签<template>、

<template>
    <!-- 组件的结构 --> 
<\template>
    
<script>
    //组件交互所需要的代码(包括数据、方法等等)
</script>
    
<style >
    /*组件的样式*/
</style>   
 

  • 我们可以创建一个学校组件school.vue

<!-- 此标签不会参与标签的编译 -->
<template>
  <div class="demo">
    <h2>学校名称:{{ schoolName }}</h2>
    <h2>学校地址:{{ address }}</h2>
    <button @click="showName">点我提示学校名称</button>
  </div>
</template>
​
​
<script>
//ES6中模块化暴露(默认暴露)
//创建组件Vue.extent是可以省略的,直接暴露组件的配置对象即可
export default Vue.extent({
  //组件名
  name: "School",
​
  data() {
    return {
      schoolName: "qiludongyedaxue",
      address: "济南",
    };
  },
​
  methods: {
    showName() {
      alert(this.schoolName);
    },
  }
  
});
</script>
​
<style >
.demo {
  background: orange;
}
</style>

  • 创建student.vue

<!-- 此标签不会参与标签的编译 -->
<template>
  <div >
    <h2>学生姓名:{{ studentName }}</h2>
    <h2>学生年龄:{{ age }}</h2>
  </div>
</template>
​
​
<script>
export default Vue.extent({
  //组件名
  name: "Student",
​
  data() {
    return {
      studentName: "张三",
      age: 18,
    };
  },
​
});
</script>
​
<style ></style>

  • 创建App.vue,汇聚所有组件

<template>
  <div>
    <School></School>
    <Student></Student>
  </div>
</template>
​
<script>
//引入组件
import School from "./School.vue";
import Student from "./Student.vue";
​
export default {
  name: "App",
​
  components: {
    School,
    Student,
  },
};
</script>
​
<style>
</style>
  • main.js文件会创建Vue实例

    入口文件,一切的活都是从这里开始的

//关闭开发环境时的生产提示
Vue.config.productionTip = false
​
import App from './App.vue'
​
​
new Vue({
    el:'#root',
    components:{
        App
    }
})
  • index.html

<!DOCTYPE html>
​
<html>
​
<head>
    <meta charset="UTF-8">
    <title> 联系单文件组件语法</title>
    <!-- 在这个地方引入会出现main.js会出现一个问题,就是main.js找结构,但是发现结构还没有出来 -->
    <!-- <script type="text/javascript" src="./main.js"></script> -->
</head>
​
​
<body>
    <div id="root"> 
        <!-- 容器里面的模板 -->
        <App></App>
    </div>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../js/vue.js"></script>
    <!-- 先让模板出来再引入 -->
    <script type="text/javascript" src="./main.js"></script>
</body>
​
</html>

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱布朗熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值