用原生的方式写vue组件之深度剖析组件内部的原理

news2024/11/16 21:01:25

目录

  • 前言
  • 一,对组件的复习及理解
  • 二,模块化与组件化
  • 三,用原生的方式写vue组件
    • 3.1 准备工作
    • 3.2 创建组件
    • 3.3 组件中的data为什么是函数式写法
    • 3.4 组件中的template
  • 四,注册组件
  • 五,使用组件
  • 六,全局组件
  • 七,细节问题
    • 7.1 如果把组件代码挪到实例对象后还可以正常运行么
    • 7.2 this指向问题
  • 八,完整代码
  • 九,知识点总结
  • 后记

前言

初学组件相关知识时,是在脚手架之后,在学习的那段时间记住了组件的很多内容,然时间一长很容易忘记,可见,很多东西,我们需要更深层次的理解其中原理,绝非死记硬背。

本篇文章,笔者将带领大家去用原生的方式创建组件,注册组件,以及应用组件,且更深层次的带领大家了解组件,以及探索组件内部的一些部分为何要这么写。

一,对组件的复习及理解

(建议复习升华,若很熟悉可以跳过)

初学前端,使用前端三件套编写网页,无非就是三部分:html,css,js。若有一个已经写好了的网页,还需要写另一个差不多的,则需要复用已经写好了的网页。复用时多数是复制粘贴,并且还需要作出更改,十分不便。

而组件化则是帮我们把网页上的每一个部分拆分出来,好似一块块砖,在需要时直接搬运即可,十分方便。

这里用几张图来说明问题:
这是一个网页的结构图,里面有四个组件,每个组件内部都封装了相关的html,css,js。
在这里插入图片描述
现在网页二想要用网页一的头部,直接把头部组件拿过来用即可:
在这里插入图片描述
上面两张图直观的告诉了大家组件的用法。下面同样通过两张图来说明组件的嵌套,助大家更好的理解组件:
这是一个网页的示意图,这个网页是由一个个组件组合而成的:
在这里插入图片描述
上面是网页的结构图,现在将这张结构图拆分成组件的嵌套:
在这里插入图片描述
总结一下,组件的标准定义:实现应用中局部功能代码和资源的集合。

二,模块化与组件化

当我们用三件套做一个项目,或者是用nodejs写一个后台,应用中的js都以模块化来编写,那么这个应用就是一个模块化应用;

同理,当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化应用。在使用vue做项目时我们会用到很多的组件,做出的也都是组件化应用。因此,学习好组件的相关知识十分有必要。

三,用原生的方式写vue组件

3.1 准备工作

既然是用原生的方式编写,那么vue的页面结构与示例对象也是原生的,并且需要引入vue.js文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="root"></div>

    <script>
        new Vue({
            el: '#root',
            data: {},
            methods: {}
        })
    </script>
</body>
</html>

这里我们写用最基础的差值语法写出一个结构:

    <div id="root">
        <h2>姓名: {{ name }}</h2>
        <h2>年龄: {{ age }}</h2>
    </div>

    <script>
        new Vue({
            el: '#root',
            data: {
                name: '巧克力小猫猿',
                age: 20
            },
            methods: {}
        })

效果:
在这里插入图片描述

3.2 创建组件

现在提出一个需求,写出一个和上面结构一样的组件。既然是写组件,那么#root文件内部的结构可以直接删掉或者注释掉:
在这里插入图片描述
现在开始创建组件,给这个组件取名字为user。这里需要借助一个内部的api:Vue.extend()。这个方法内部的参数是对象

        const user = Vue.extend({
        })

在使用原生写法创建Vue实例时,会有el,data,methods等等属性。在组件中写法类似,但是也有区别。我们先来看一下最初的Vue实例中的一些写法:
在这里插入图片描述
接着我们看一下组件的写法:
在这里插入图片描述
肉眼可见的不同之处有两点:第一点,组件中不写el,Vue实例对象中的el是为了告诉Vue这个实例对象控制哪块区域,而组件是要多次复用的,在写组件的时候是无法知晓组件要用到哪里去的,所以不需要写el;第二点,组件中的data写法和vue中的不太一样。这一点,我将在接下来详细讲解。

3.3 组件中的data为什么是函数式写法

data有两种写法,一种是函数式,一种是对象式。为什么在组件中写data时要写成函数式?本节将探索这个问题。

大家请看如下代码:

    <script>
        var data = {a: 1, a: 2}
        var x = data
        var y = data
    </script>

在这里,data是一个对象,把data的值赋给了x和y,于是x和y也是对象。现在,我在控制台改动x中的a的值:
在这里插入图片描述
a的值被成功改变。但是现在我们再来看一下y中的a,会发现y中的a也被改变了。
在这里插入图片描述
这里可以看出,改变了x中的东西,y中的东西也会连带发生改变。那么如果data写成函数呢,会不会也出现这种情况?这里data函数返回的同样也是一个对象,且同样另x和y等于data,唯一的区别就在于data是一个函数:
在这里插入图片描述
接着再重复刚刚在控制台对x和y的操作:
在这里插入图片描述
可以看到,x中的a被成功改动,但是y中的a没有被连带改动。

通过上面的讲解,相信大家已经知道为什么组件中的data是函数形式而非对象了:因为组件是会被用在很多vue实例中去的,如果data是对象形式,则一个实例对data改动就会影响其他组件。可如果data是函数形式,则不会出现这类问题。因此,组件中的data是函数形式。

3.4 组件中的template

上述的操作流程完成,我们已经完成了组件中的数据部分。可是在需求中,要求使用组件能够出现如下结构:
在这里插入图片描述
那么,在组件中如何写html结构呢?则需要利用template。

我们来聊一聊template:

template又名模板语法,大家也可以理解为它是一个占位符,在vue脚手架中组件的使用至关重要,后面写博客也尽量涉及到这个内容,欢迎关注。在本节博客中,我们只需要了解,template作为占位符,它的内部必须有一个div作为根节点。由于template是一个模板语法,所以需要解构(了解)。

这里大家可以记住它在组件中的写法:

            template: `
                <div>        
                    <h2>姓名: {{ name }}</h2>
                    <h2>年龄: {{ age }}</h2>
                </div>
            `,

至此,我们的组件已经写好。我们来看一下这个组件的完整写法:

        //创建user组件
        const user = Vue.extend({
            data() {
                return {
                    name: '巧克力小猫猿',
                    age: 20
                }
            },
            template: `
                <div>        
                    <h2>姓名: {{ name }}</h2>
                    <h2>年龄: {{ age }}</h2>
                </div>
            `,
            methods: {}
        })

四,注册组件

在创建完成组件后,如果想在某一个Vue实例中使用,现需要在此实例中注册该组件。注册方法很简单,如下:
在这里插入图片描述
在Vue中协商components(组件)的配置项,内部是以键值对的形式去注册组件:

组件名:组件

组件名是自己取的,而组件是原先写好的组件名。在js中,如果组件名和组件一样,可以简写为:
在这里插入图片描述
自此,组件注册成功。

五,使用组件

如果在一个实例中注册了user组件,则可以在该实例所管理的root容器中使用该组件。使用方式也很简单,如下图,写一个标签,标签名为组件名,即可。
在这里插入图片描述
最后在浏览器中的效果和我们的需求一样:
在这里插入图片描述
以上,就是一个组件从创建,到注册,到使用的完整写法。

六,全局组件

在前面的内容中,我们为#root容器创建了一个管理它的Vue实例对象,写好了一个user组件,并在管理#root容器的Vue实例对象中注册user组件,在#root中使用,这是一个完整的过程。现在有一个疑问,如果我新写一个名为#root2的容器并为其创建一个新的Vue实例对象,请问,可以直接使用user组件么?

答案是不行的,必须要在#root2对应的Vue实例对象中注册user组件,才可以在#root2中使用。原因是,刚刚写的user是一个局部组件

如何写一个组件让所有的实例对象都可以直接使用呢?全局组件可以帮我们解决问题。

        const intro = Vue.extend({
            data() {
                return {
                    address: '武汉'
                }
            },
            template: `
            <div>
                <h2>地址: {{ address }}</h2>
            </div>
            `
        })
        Vue.component('intro', intro)

上述代码最后一行则是将intro注册为了全局组件。注册后如果想要在某个实例对象中使用intro,可以不单独注册,直接放入容器中使用:
在这里插入图片描述
在这里插入图片描述

七,细节问题

7.1 如果把组件代码挪到实例对象后还可以正常运行么

答案是不可以的。组件的内容必须写在实例对象的前面。=

这是报错信息:
在这里插入图片描述
翻译过来就是:在初始化之前没有办法获取到user。

结合生命周期的知识可知,在mounted前都是初始化的过程。而在初始化过程中会解析模板,生成虚拟Dom。而在初始化时无法解析user,则卡在了这一步。无法继续运行。所以组件内容要写在需要用到的实例对象前面。

如果有读者问,js不是有预解析功能么,如果对这块有疑问,可以参考我之前写的博客:javascript预解析

7.2 this指向问题

之前我有写过Vue中this的指向问题相关博客:Vue中关于this指向的重要原则

但是那篇文章中只有一个Vue实例对象。在应用中,会用到多个组件。那么this该指向如何?

请看如下代码:

页面结构如下:

    <div id="root">
        <user></user>
    </div>

    <div id="root2">
        <user></user>
    </div>

js代码如下:

        //创建user组件
        const user = Vue.extend({
            data() {
                return {
                    name: '巧克力小猫猿',
                    age: 20
                }
            },
            template: `
                <div>        
                    <h2>姓名: {{ name }}</h2>
                    <h2>年龄: {{ age }}</h2>
                    <button @click='add'>点此按钮年龄加1</button>
                </div>
            `,
            methods: {
                add() {
                    this.age
                }
            }
        })

        const intro = Vue.extend({
            data() {
                return {
                    address: '武汉'
                }
            },
            template: `
            <div>
                <h2>地址: {{ address }}</h2>
            </div>
            `
        })
        Vue.component('intro', intro)
        var vm1 = new Vue({
            el: '#root',
            data: {},
            components: {
                user
            }
        })

        var vm2 = new Vue({
            el: '#root2',
            data: {},
            components: {
                user
            }
        })

这里我给user新添了一个button按钮,点击后年龄加1,放在页面里的效果:
在这里插入图片描述
在两个容器中使用该组件,但是点击年龄加一互不影响,这一点可以说明,this在组件中的指向是
调用它的Vue实例

八,完整代码

这里放上本节内容相关的完整代码,读者有兴趣可以在此代码的基础上进行探索。(Vue.js文件需要自己重新引入)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="root">
        <user></user>
    </div>

    <div id="root2">
        <user></user>
        <intro></intro>
    </div>

    <script>

        //创建user组件
        const user = Vue.extend({
            data() {
                return {
                    name: '巧克力小猫猿',
                    age: 20
                }
            },
            template: `
                <div>        
                    <h2>姓名: {{ name }}</h2>
                    <h2>年龄: {{ age }}</h2>
                    <button @click='add'>点此按钮年龄加1</button>
                </div>
            `,
            methods: {
                add() {
                    this.age
                }
            }
        })
        const intro = Vue.extend({
            data() {
                return {
                    address: '武汉'
                }
            },
            template: `
            <div>
                <h2>地址: {{ address }}</h2>
            </div>
            `
        })
        Vue.component('intro', intro)
        var vm1 = new Vue({
            el: '#root',
            data: {},
            components: {
                user
            }
        })

        var vm2 = new Vue({
            el: '#root2',
            data: {},
            components: {
                user
            }
        })
    </script>
</body>

</html>

九,知识点总结

1.使用组件三大步骤:创建-注册-使用;
2.如何定义组件:使用Vue.extend()内部api;
3.组件内部el不要写:最终左右组件都要经过一个vm管理,而vm中的el决定服务哪个容器;
4.data必须写成函数:避免组件被复用时,数据存在引用关系;
5.template可以用于配置组件结构;
6.组件内部this指向调用它的Vue实例;
7.局部注册于全局注册;
8.编写组件的标签写法。

后记

本节内容以我自己的思路带领读者了解了原生组件的写法以及应用。组件在原生中与在脚手架中的使用是有区别的。之所以在原生中讲解这么多是希望读者朋友在学习的过程中不是靠死记硬背去记如何写组件,而是从更加细致的原理处去理解一些写法为什么要这么写。

后续内容我会继续完善,欢迎大家为我提出问题。后续博客会努力更新,希望得到大家的关注和支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/150080.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里云服务器ECS购买教程

本文是关于阿里云主机&#xff08;服务器ECS&#xff09;购买流程的一个详细介绍。阿里云服务器&#xff08;Elastic Compute Service&#xff0c;简称 ECS&#xff09;是一种简单高效、处理能力可弹性伸缩的计算服务&#xff0c;帮助您快速构建更稳定、安全的应用&#xff0c;…

机器学习实战教程(十二):线性回归提高篇

一、前言本篇文章讲解线性回归的缩减方法&#xff0c;岭回归以及逐步线性回归&#xff0c;同时熟悉sklearn的岭回归使用方法&#xff0c;对乐高玩具套件的二手价格做出预测。二、岭回归如果数据的特征比样本点还多应该怎么办&#xff1f;很显然&#xff0c;此时我们不能再使用上…

【Elsevier出版社】1区智能物联网类SCIEI,审稿友好~

1区智能物联网类SCI&EI 【出版社】Elsevier 【期刊简介】IF&#xff1a;5.5-6.0&#xff0c;JCR1区&#xff0c;中科院3区 【检索情况】SCI&EI 双检&#xff0c;正刊 【参考周期】3个月左右录用 【截稿日期】2023.2.28 【征稿领域】 ①物联网辅助的智能解决方案…

送给SQL开发者的一份新年礼物!麦聪软件发布一款纯Web化SQL开发工具,免安装还免费!

2023年新年伊始&#xff0c;麦聪软件再次迎来一个好消息&#xff1a;一款100%自主研发的纯Web化SQL开发工具——SQL Studio 1.0正式发布。这款产品让SQL开发者在Navicat、DBeaver之外&#xff0c;又多一款值得信赖的SQL开发工具可用。 图片 目前&#xff0c;SQL Studio 1.0面向…

qt读写xml文件(DOM和SAX两种方式)

一、XML简介&#xff1a; XML, 全称为扩展标记语言, 可用来标记数据、定义数据类型&#xff0c;是一种允许用户对自己的标记语言进行定义的源语言。XML非常适合万维网传输&#xff0c;提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据&#xff0c;是Internet环境…

纵向联邦线性回归实现-Federated Machine Learning Concept and Applications论文复现

本实验的算法实现思路来自这篇论文Federated Machine Learning Concept and Applications 文章目录场景介绍同态加密算法python的phe库实现了加法同态加密角色1角色2传统的线性回归纵向联邦线性回归纵向联邦线性回归代码实现导入工具包准备数据使用普通线性回归训练搭建训练过程…

什么神仙操作,用代码能画这样的图

大家好&#xff0c;我是车辙。不知道同学们画流程图或者时序图一般用的什么软件&#xff1f;Visio 还是 Process On 或者语雀&#xff1f; 因为公司原因&#xff0c;在很多情况下&#xff0c;我一般用语雀画流程图或者思维导图。不过凡事也有例外&#xff0c;对于比较简单的图…

你的电路是抄来的还是算出来的?

在你看这篇文章之前&#xff0c;我想提出几点说明&#xff1a; &#xff08;1&#xff09;最近在看拉扎维的书&#xff0c;写下来这些东西&#xff0c;这也只是我个人在学习过程中的一点总结&#xff0c;有什么观点大家可以相互交流&#xff1b;&#xff08;2&#xff09;不断的…

立创eda专业版学习笔记(3)(隐藏部分飞线)

又到了喜闻乐见的隐藏gnd飞线环节&#xff0c;我发现这个专业版的操作和标志版不一样&#xff0c;我想试一试这个标题的搜索结果&#xff0c;发现有用的结果还是很少&#xff0c;于是我也随便总结了一下&#xff0c;算是添砖加瓦吧。 原来的飞线是这个样子的&#xff1a; 现在我…

巧妙解决appleid问题答案忘了的问题

先说下这个问题解决办法的目标——主要是为了释放被占用的appleid邮箱&#xff0c;而如果你想保留该appleid并且正常使用的话&#xff0c;那么需要付出一点代价&#xff0c;也是可以做到的。 我最近就碰到这种情况&#xff0c;某个邮箱被appleid占用了&#xff0c;问题答案因为…

从实战出发,聊聊缓存数据库一致性

在云服务中&#xff0c;缓存是极其重要的一点。所谓缓存&#xff0c;其实是一个高速数据存储层。当缓存存在后&#xff0c;日后再次请求该数据就会直接访问缓存&#xff0c;提升数据访问的速度。但是缓存存储的数据通常是短暂性的&#xff0c;这就需要经常对缓存进行更新。而我…

Linux常用命令——lsb_release命令

在线Linux命令查询工具 lsb_release 显示发行版本信息 补充说明 LSB是Linux Standard Base的缩写&#xff0c;lsb_release命令用来显示LSB和特定版本的相关信息。如果使用该命令时不带参数&#xff0c;则默认加上-v参数。 -v 显示版本信息。 -i 显示发行版的id。 -d 显示该…

2023 Real World CTF 体验赛 --- wp

文章目录misc&#x1f411;了拼&#x1f411;webEvil MySQL ServerBe-a-Language-ExpertBe-a-Wiki-HackerYummy ApiApacheCommandTextmisc &#x1f411;了拼&#x1f411; 游戏类题目&#xff0c;直接打开js文件搜索rwctf&#xff0c;发现flag rwctf{wellcome_to_the_rwct…

跟着开源项目学java8-从支持最大密码重试次数的提交看redis的场景化使用和基于jdk的schedule的异步延迟日志记录策略

我们这里要实现的功能是登录时添加账号登录错误时最大错误次数和锁定时间&#xff0c;功能不复杂&#xff0c;这次提交里面我们主要来看下一个项目里面一个业务功能怎样写更加优雅 核心实现 我们先来看核心实现的思路 首先是 login 方法重写&#xff0c;进入 loadUserByUser…

【vue2】Vue Cli脚手架与VueTools的安装详解

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;Vue Cli脚手架与VueTools的安装详解 目录 一、vue-cli脚手架工具的安装及文件介绍 1.v…

ArcGIS基础实验操作100例--实验72土地利用变化分析

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验72 土地利用变化分析 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&…

ArcGIS 制图流程 非常详细

如何在ArcMap中从头到尾制作一幅专题图&#xff1f;你可以看本编教程&#xff0c;从准备数据到最终导出成图&#xff0c;一步一步进行操作&#xff0c;一定可以教会你。 至于为何使用英文版软件&#xff0c;你如果作图就会知道一般经纬度都是利用英文显示&#xff0c;不然最终…

微信小程序实现左边图片右边文字效果

实现的效果&#xff1a; xml布局文件&#xff1a; <view class"chuxingItem"> <image class"img" src"/pages/image/banche.png"></image> <view style"font-size: 30rpx;margin-left: 15rpx;">班车查询</…

Leetcode:513. 找树左下角的值(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 递归&#xff1a; 原理思路&#xff1a; 层序遍历&#xff1a; 原理思路&#xff1a; 问题描述&#xff1a; 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至…

kaggle平台学习复习笔记 | Data Visualization | Seaborn

目录1.hello Seaborn2.Line Charts3.Bar Charts and Heatmaps4.Scatter PlotsDistributions5.Choosing Plot Types and Custom Styles1.hello Seaborn import pandas as pd pd.plotting.register_matplotlib_converters() import matplotlib.pyplot as plt %matplotlib inline…