Vue3.0(二):Vue组件化基础 - 脚手架

news2024/11/28 12:31:34

Vue组件化基础 - 脚手架

Vue的组件化

  • 我们在处理一些任务量比较庞大的工作时候,会将工作内容进行拆分,分步骤完成

  • 而组件化的思想正式如此,对于一个庞大的项目,我们可以将其拆分成一个个的小功能,分步骤进行实现

  • 组件化是Vue的核心思想

    • 在前面的学习中,我们 在createApp中传入了一个App对象,这个对象的本质其实就是一个组件
    <div id="app">
        <div v-for="item in arr" :key="item">{{item}}</div>
    </div>
    <script>
        //使用Vue
        const App = {
            data() {
                return {
                    arr: [1, 2, 3],
                };
            },
        }
        const app = Vue.createApp(App);
        //挂载
        app.mount("#app");
    </script>
    
    • 任何应用都会被抽象成一颗组件树

image.png

注册组件的方式

分为全局组件注册:任何地方都可以用

局部组件注册:

注册全局组件

  • 全局组件需要使用 app进行注册
  • 通过 component方法传入组件名称,组件对象即可注册一个全局组件
<div id="app">
    <my-component></my-component>
</div>
<script>
    const App = {};
    //全局组件对象
    const myComponent = {
        template: `
        <h2>我是一个组件</h2>
        `,
    };
    //使用Vue
    const app = Vue.createApp(App);
    //注册全局组件
    //传入全局组件的名称以及对象
    app.component("my-component", myComponent);
    //挂载
    app.mount("#app");
</script>
  • 组件的名称
    • 使用短横线分隔符:my-component进行命名,使用的时候 <my-component></my-component>
    • 使用大驼峰命名法:MyComponent进行命名,使用的时候 <my-component></my-component>或者 <MyComponent></MyComponent>

注册局部组件

全局组件往往是在程序一开始的时候,就会全局组件注册完成,但是有些组件我们并为使用过,在打包的时候,会增加打包文件的体积

因此局部组件是开发中常用的

  • 通过 components属性进行注册
  • 要明确要在哪里使用该组件
<div id="app">
    <my-component></my-component>
    <my-item></my-item>
</div>
<script>
    const App = {
        components: {
            //key就是组件的名称,后面跟着组件对象
            "my-component": {
                template: `
                <h2>我是一个组件</h2>
            `,
            },
            //第二个局部组件
            MyItem: {
                template: `
                <h2>我是一个组件Item</h2>
                `,
            },
        },
    };
    //使用Vue
    const app = Vue.createApp(App);
    //挂载
    app.mount("#app");
</script>
  • 局部组件与全局组件的区别就是
    • 全局组件可以在任意组件内使用
    • 而局部组件只能在定义的组件的内部使用:比如 MyItem组件不能再 my-component组件中使用

Vue的开发模式

  • 在真正开发Vue项目的时候,我们是通过创建一个 Vue文件进行开发的
  • 而浏览器是不认识 Vue文件的,此时我们可以借助打包工具 webpack/vite等,进行打包
  • Vue文件转换成JS对象,这样浏览器就可以识别

image.png

单文件的特点

上面说的Vue文件实际上就是一个单文件

  • 以下就是一个简单的 Vue文件

image.png

Vue CLI脚手架

为了让浏览器能够正常渲染Vue文件,可以使用Vue CLI搭建相关环境

  • 在真实的开发中,我们通常会使用 脚手架来创建一个项目,Vue项目我们使用的就是Vue的脚手架
  • Vue的脚手架就是 Vue CLI
    • 我们可以通过 CLI选择项目的配置和创建出我们的项目
    • Vue脚手架已经 内置了webpack的相关配置,不需要从零开始配置

安装和脚手架

  • 通过 npm install @vue/cli -g全局安装 Vue脚手架

image.png

  • 接下来我们就可以使用 Vue脚手架创建项目了
  • 使用 vue create 项目名称创建一个项目
    • 注意 项目名称中不能含有大写字母
  • 接下来选择项目的配置项
    • 我们选择自定义配置项

image.png

  • 根据个人需求选择下面的选项即可

image.png

  • 选择创建Vue项目的版本
    • 此处我们选择 Vue3版本

image.png

  • 针对于 Babel等工具配置项的选项
    • 我们选择将配置项单独生成一个文件

image.png

  • 以下还有一些内容的配置

image.png

  • 而后等待项目自动生成即可
  • 进入到项目目录中,使用 npm run serve命令即可运行项目

Vue项目的目录分析

  • 整体的项目目录如下

image.png

  • node_modules:项目的依赖包
  • public:里面的两个文件是项目的图标,以及html模板(用于打包时候自动生成的html)
  • src:用于编写源代码
  • .browserslistrc:进行浏览器适配的,比如写了ES6+以上的代码,根据适配的浏览器,决定是否转化,会在caniuse中去查找相应的内容
  • .gitignore:git的忽略文件
  • babel.config.js:babel工具的配置项
  • jsconfig.json:给vscode使用,可以拥有更好的友好提示
  • package-lock.js package.json:安装依赖的版本,执行脚本等
  • vue.config.js:可以在这里对webpcak的打包工具进行设置等操作

src文件夹中的main入口文件,以及App.vue文件

  • main.js是项目的入口文件
    • 这和之前写的代码时一样的
    • 之前我们通过 Vue.createApp(App)创建一个Vue实例,而这是通过 import引入Vue
    • 该文件中,还引入了 App.vue文件,并进行挂载
    • 在此处我们可以注册全局组件
import { createApp } from "vue";
import App from "./App.vue";
import HelloWorld from "./components/HelloWorld";

const app = createApp(App);
//注册全局组件
//直接在任意vue文件中使用即可
app.component("hello-world", HelloWorld);

//挂载
app.mount("#app");
  • App.vue文件就是根组件
    • 可以在里面注册局部组件
<template>
  <h2>{{ title }}</h2>
  <HelloWorld></HelloWorld>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
  //注册局部组件
  components: {
    //这是对象的增强写法,等同于HelloWorld:HelloWorld
    HelloWorld,
  },
  data() {
    return {
      title: "zhangcheng",
    };
  },
};
</script>

<style></style>
  • 因此对于今后的开发就变成了以下的情况

image.png

其他创建vue项目的方法

使用npm init vue@latest

  • 运行 npm init vue@latest命令创建项目

    • 首先会安装一个本地工具 : create-vue
    • 使用 create-vue创建一个vue项目
  • 且是使用 vite进行打包的,不是使用webpack进行打包

  • 输入完命令,会询问是否安装 vue-create工具

    • 输入 y

image.png

  • 而后根据需要进行如下配置

image.png

  • 最后根据提示,安装相应的依赖包,即可运行项目

image.png

组件化 - 组件间通信

认识组件的嵌套

  • 在根组件中,我们可以引入各种小组件,完成组件嵌套
<template>
  <div>
    <!-- 头部 -->
    <header-com></header-com>
    <!-- 内容 -->
    <content-com></content-com>
    <!-- 底部 -->
    <footer-com></footer-com>
  </div>
</template>

<script>
import HeaderCom from "./components/HeaderCom.vue";
import ContentCom from "./components/ContentCom.vue";
import FooterCom from "./components/FooterCom.vue";
export default {
  //注册局部组件
  components: {
    HeaderCom,
    ContentCom,
    FooterCom,
  },
  data() {
    return {
      title: "zhangcheng",
    };
  },
};
</script>

<style></style>

父子组件之间的通信

  • 父组件传递给子组件 : 通过props属性
  • 组组件传递给父组件:通过$emit触发事件

image.png

组件间通信-父传子

在以上案例中,相当于是App.vue中的数据,要传递给HeaderCom.vue/ContentCom.vue/FooterCom.vue

  • 在子组件中通过 props接收父组件传递过来的参数

  • 什么是Props

    • Props是可以在组件上注册一些自定义的attribute
    • 父组件给 这些attribute赋值子组件通过attribute的名称获取对应的值
  • Props有两种常见的用法

    • 方式一:字符串数组
      • 弊端:不能对传入的数据进行类型验证
      • 没有默认值
    • 方式二:对象类型

image.png

type的类型都是哪些
  • 常见的类型
String
Number
Boolean
Array
Object
Date
Function
Symbol
对象类型的其他写法
  • 接收的是一个对象/数组
props: {
   //若是对象类型,则需要用函数返回
    obj:{
        type:Object,
        //因为对象类型,多个组件共享该对象的话,其中一个组件进行了更改,所有的都会更改
        default:()=>{
            return {name:"zhangcheng"}
        } 
    },
    arr:{
        type:Array,
        default(){
            return [1,2,3]
        }
    }
  },
  • 声明多个类型
props: {
    //可以接收多个类型
    age: [Number,String],
  },

组件间通信-子传父

在以上案例中,相当于是HeaderCom.vue/ContentCom.vue/FooterCom.vue中的数据,要传递给App.vue

  • 用到子传父的时候
    • 子组件中有一些事件发生的时候,比如子组件中发生了点击,父组件需要切换内容
    • 子组件中有一些内容想要传递给父组件
  • 用法
    • 首先在子组件中 通过 $emit发射一个事件
    • 在父组件引用子组件的地方 使用发射的事件
    • 在父组件中定义一个事件 用于接收子组件传入的数据

image.png

  • Vue3中,增加了emits属性,父组件在使用子组件发射参数的时候能够得到友好的提示,同时可以对其进行验证(很少用)

image.png

非Prop的attribute

  • 当子组件中设置了 prop进行接收父组件传进来的数据,则该attribute就是prop的attribute
  • 但是 当父组件传入了一个attribute,是子组件中没有声明的,那就是非prop的attribute
    • class没有在子组件的prop中声明,此时class就是 非prop的attribute
<childCom class="active"></childCom>
  • 非prop的attribute会自动给子组件的根节点
//父组件引用了子组件
<childCom class="active"></childCom>

-----------------------
//子组件
<template>
	<div>
    	其他元素
    </div>
</template>
//相当于在子组件中的div中添加了class="active"
  • 如果我们不想,默认添加给根节点,同时还想将其给子组件中的其他元素
    • 首先通过 inheritAttrs属性禁止非prop的attribute添加到根节点中
    • 之后通过 $attrs.属性名进行获取
<template>
  <div>
    <div :class="$attrs.class">{{ name }}</div>
    <div v-bind="$attrs">{{ age }}</div>
  </div>
</template>

<script>
export default {
    //阻止非prop的attribute添加到根节点中
  inheritAttrs: false,
  props: ["name", "age"],
  data() {
    return {};
  },
  methods: {},
};
</script>

插槽 - Slot

子组件中的数据可以根据传入的数据进行变化

而子组件中的元素是否可以?

  • 比如,现在有一个子组件,我们想让其根据不同的要求,显示 文本/按钮/图片等内容
  • 此时我们就需要用到 slot插槽这个功能

基本使用

  • 用法
    • 在子组件中,写入插槽
    • 父组件引用子组件的内部写入想要显示的元素即可

image.png

默认内容

当我们没有给子组件传入内容,但是又想让子组件默认显示一些内容,可以在slot中写入默认的元素

image.png

多个插槽-具名插槽

  • 如果子组件中,有多个插槽,应当使用 具名插槽
  • 在 子组件的插槽中 使用 name属性,给插槽起名字
  • 父组件中传入元素的时候 使用 v-slot:插槽名字
  • 不带name属性的slot,实际上有一个默认不显示的名字,为 default
-----子组件
<template>
	<div>
        <div class="left">
            <slot name="left"></slot>
    	</div>
        <div class="right">
            <slot name="right"></slot>
    	</div>
    </div>
</template>


-------父组件
<template>
	<childCom>
        <!--需要使用template进行包裹-->
    	<template v-slot="left">
			<button>
                按钮
    		</button>
		</template>
		<template v-slot="right">
			<span>
                文本
    		</span>
		</template>
    </childCom>
</template>
  • 具名插槽的简写 可以用 #代替v-slot
-------父组件
<template>
	<childCom>
        <!--需要使用template进行包裹-->
    	<template #"left">
			<button>
                按钮
    		</button>
		</template>
		<template #"right">
			<span>
                文本
    		</span>
		</template>
    </childCom>
</template>

动态插槽名

当我们在父组件中使用 v-slot的时候,可以指定元素插入到哪个插槽中

但是我们不希望冒号后面的内容写死,即 v-slot:“right”,right是动态的

<AddComponts @add="countAdd">
    <!--将冒号后面,写上 [],里面写入变量即可-->
    <template v-slot:[posion]>
<button>123</button>
    </template>
</AddComponts>

作用域插槽

  • 首先看一下需求
    • 父组件给子组件传递了data数据
    • 子组件中有一个插槽
    • 父组件引用了子组件的插槽,且填入元素
    • 想让填入的元素中的数据,使用父组件传给子组件的数据
  • 此时我们就可以使用作用域插槽

image.png

image.png

非父子组件通信

  • 在实际开发中,我们有时候会遇到,非父子组件之间的传值
  • 比如 App.vue向SearchCom.vue传值,或者MainCom.vue向FootCom.vue传值

image.png

  • 通常我们在非父子组件通信的时候,使用的是 Provide/Inject(不常用)和事件总线

Provide和Inject

仅能用作有关联的组件,没有关联的组件不能使用

  • Provide和Inject用于非父子组件之间共享数据
  • 父组件有一个 provide选项来提供数据
  • 子组件有一个 Inject选项来使用这些数据
  • 同时父组件不知道要把数据传给谁,而子组件不知道数据的来源是哪里

image.png

  • 通常提供数据的一方 provide写成函数的形式
    • 若提供的数据为响应式的话,需要用到 computed函数

事件总线

以上方法的弊端就是,无法实现兄弟组件之间的通信,因此选用事件总线

  • 在Vue2版本中,Vue是有事件总线的功能 o n , on, on,emit等
  • 但是在Vue3版本中,取消了事件总线的功能,因此官方推荐使用了三方库 mitt
  • 同时我们自己也可以自己封装一个事件总线的工具函数
    • 在JS高级的文章中,有过封装
  • 首先封装一个自己的事件总线工具
class zcEventBus {
  constructor() {
    this.obj = {};
  }
  //on事件需要接收两个参数,事件名称,回调函数
  on(eventName, callBackFn) {
    //采用对象的结构,一个事件名称,后面跟着数组,可以包含多个事件
    //{eventName:[fn1,fn2]}
    //但是第一次执行的时候,this.obj[eventName]不是一个数组,需要进行判断
    let eventArr = this.obj[eventName];
    //第一次肯定是undefined,当!eventArr的时候,为true
    if (!eventArr) {
      //将this.obj[eventName]初始化数组
      eventArr = [];
      this.obj[eventName] = eventArr;
    }
    //相当于在this.obj[eventName]中push了事件
    eventArr.push(callBackFn);
  }
  //emit事件需要接收两个参数,事件名称,以及参数
  emit(eventName, ...arg) {
    console.log(eventName);
    //需要遍历eventName对用的事件数组,并依次执行
    //首先判断是否存在,不存在直接返回
    let eventArr = this.obj[eventName];
    if (!eventArr) return;
    //若存在,则直接遍历执行
    for (const fn of eventArr) {
      fn(...arg);
    }
  }
}

export default new zcEventBus();
  • 在组件中引用
import EventBus from "./components/EventBus.vue";
  • 在提供数据的一方使用 emit方法
emitData() {
    //传入事件的名称,以及参数
    zcEventBus.emit("zcEventBus", "zhangcheng");
},
  • 在接收数据的一方使用 on方法
created() {
    zcEventBus.on("zcEventBus", (data) => {
        console.log("父组件收到了数据", data);
    });
},

image.png

  • 规范的写法,应当在 unmounted生命周期中取消相应的事件总线

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

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

相关文章

Axure RP9原型设计工具使用记录:基础操作

Axure RP9使用记录一 &#x1f4da;第一章 前言&#x1f4d7;背景&#x1f4d7;目的 &#x1f4da;第二章 基础介绍及操作&#x1f4d7;页面功能总览&#x1f4d7;基础操作&#x1f4d5;设置样式&#x1f4d5;设置交互&#x1f4d5;设置组合&#x1f4d5;设置动态面板&#x1f…

在线JSON转SQL工具

在线JSON转SQL - BTool在线工具软件&#xff0c;为开发者提供方便。在线JSON转SQL工具可以将JSON文件中的数据或者JSON对象转换为SQL插入语句&#xff0c;方便用户将数据导入到数据库中。用户可以通过简单的界面上传JSON文件&#xff0c;或者文本框输入&#xff0c;点击JSON转S…

云服务器也能挂游戏 安卓模拟器

安卓模拟器云服务器 什么是BlueStacks模拟器主机&#xff1f; 特网科技基于Windows操作系统预装了BlueStacks Android模拟器您能够通过Android模拟器安装Android应用程序、如APP游戏、安卓APP、APP游戏等。 我可以在主机上安装应用程序吗&#xff1f; 你可以在BlueStacks模…

适合大型企业的云计算服务器有哪些?

随着云计算技术的不断发展&#xff0c;越来越多的企业开始采用云计算服务来降低成本、提高效率。对于大型企业而言&#xff0c;选择适合的云计算服务器非常重要&#xff0c;因为它将直接影响企业的业务运营和数据安全。本文将介绍适合大型企业的云计算服务器类型&#xff0c;以…

使用Pycharm安装Python的库

1.点击文件-----设置&#xff08;setting&#xff09; 2.找到Python解释器&#xff0c;点击加号 3.搜索你需要的库&#xff0c;安装

介绍一个关于 JSON 可视化的网站

最近在看到一个比较好玩的网站&#xff0c;可以将 JSON以可视化的方式展现出现&#xff0c;比如存在一下JSON数据&#xff1a; {"id": "f3bbc3bc-9f34-4bf7-8a0f-7e6f6e6fbb9a","isActive": false,"age": 25,"name": "…

Docker进阶篇-轻量级可视化工具Portainer

一、简介 Portainer是一款轻量级的应用&#xff0c;它提供了图形化界面&#xff0c;用于方便地管理Docker环境&#xff0c;包括单机环 境和集群环境。 Portainer分为开源社区版&#xff08;CE版&#xff09;和商用版&#xff08;BE版/EE版&#xff09;。 官网&#xff1a;P…

1802907-91-0,Methyltetrazine-PEG4-COOH,可以与多种不同的化学基团反应

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;Methyltetrazine-PEG4-COOH&#xff0c;Methyltetrazine-PEG4-acid&#xff0c;甲基四嗪-四聚乙二醇-羧基&#xff0c;甲基四嗪-四聚乙二醇-羧酸&#xff0c;甲基四嗪PEG4羧酸&#xff0c;甲基四嗪-PEG4-羧酸 一、基…

LLMs之Llama2 70B:《Self-Rewarding Language Models自我奖励语言模型》翻译与解读

LLMs之Llama2 70B&#xff1a;《Self-Rewarding Language Models自我奖励语言模型》翻译与解读 目录 《Self-Rewarding Language Models》翻译与解读 Abstract 5 Conclusion结论 6 Limitations限制 《Self-Rewarding Language Models》翻译与解读 地址 文章地址&#xff1…

PyTorch 2.2 中文官方教程(八)

训练一个玛丽奥玩游戏的 RL 代理 原文&#xff1a;pytorch.org/tutorials/intermediate/mario_rl_tutorial.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 注意 点击这里下载完整的示例代码 作者&#xff1a; 冯元松, Suraj Subramanian, 王浩, 郭宇章。 这个…

jmeter设置定时器

前言 本文主要分享两种定时器&#xff08;同步定时器、固定定时器&#xff09;的用法&#xff0c;从作用&#xff0c;设置方法以及实例演示几个方面讲解&#xff0c;结尾还有小知识哦&#xff01;一起开始学习吧&#xff01; 一、同步定时器&#xff08;集合点&#xff09; …

Educational Codeforces Round 87 (Rated for Div. 2)D.Multiset 卡内存的修改数组

Problem - 1354D - Codeforces 我被卡了&#xff1a; 这道题看到multiset我还真写multiset&#xff0c;结果内存超限。 当然能想到想同的数存到一块&#xff0c;所以用了map&#xff0c;结果还超&#xff0c;诶呦: set肯定比map大滴&#xff0c;这里可能刚超就结束了&#x…

C++实现鼠标点击和获取鼠标位置(编译环境visual studio 2022)

1环境说明 2获取鼠标位置的接口 void GetMouseCurPoint() {POINT mypoint;for (int i 0; i < 100; i){GetCursorPos(&mypoint);//获取鼠标当前所在位置printf("% ld, % ld \n", mypoint.x, mypoint.y);Sleep(1000);} } 3操作鼠标左键和右键的接口 void Mo…

npm---设置淘宝镜像时报“certificate has expired“的错误

今天使用vue create my-app 创建项目时&#xff0c;竟然报错&#xff1a; Error: Command failed: npm info vue-cli-version-marker --json --registryhttps://registry.npm.taobao.org npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request t…

JavaSE习题 青蛙跳台阶问题

题目&#xff1a; 一只青蛙一次可以跳上 1 级台阶&#xff0c;也可以跳上2 级。求该青蛙跳上一个n 级的台阶总共有多少种跳法。 题目分析&#xff1a; 如下图所示&#xff0c;当只有一阶台阶时&#xff0c;青蛙只有一种跳法。当只有两阶台阶时&#xff0c;青蛙有两种算法&…

「Kafka」消费者篇

「Kafka」消费者篇 Kafka 消费方式 Kafka 消费者工作流程 消费者总体工作流程 新版本&#xff08;0.9之后&#xff09;的 offset 保存在 kafka 的 Topic 里&#xff0c;持久化到磁盘&#xff0c;可靠性有保障。 老版本&#xff08;0.9之前&#xff09;的 offset 保存在 Zook…

arcpy高德爬取路况信息数据json转shp

最近工作上遇到爬取的高德路况信息数据需要在地图上展示出来&#xff0c;由于json数据不具备直接可视化的能力&#xff0c;又联想到前两个月学习了一点点arcpy的知识&#xff0c;就花了一些时间去写了个代码&#xff0c;毕竟手动处理要了老命了。 1、json文件解读 json文件显…

【Python之Git使用教程001】Git简介与安装

一、简介 Git其实就是一个分布式版本的控制系统&#xff0c;在分布式版本的控制系统&#xff0c;大家都拥有一个完整的版本库&#xff0c;不需要联网也可以提交修改&#xff0c;所以中心服务器就显得不那么重要。由于大家都拥有一个完整的版本库&#xff0c;所有只需要把各自的…

Matplotlib热力图的创意绘制指南【第54篇—python:Matplotlib热力图】

文章目录 Matplotlib热力图的创意绘制指南1. 简介2. 基本热力图3. 自定义颜色映射4. 添加注释5. 不同形状的热力图6. 分块热力图7. 多子图热力图8. 3D热力图9. 高级颜色映射与颜色栏设置10. 热力图的动态展示11. 热力图的交互性12. 标准化数据范围13. 导出热力图 总结&#xff…

【C++】- 继承(继承定义!!基本格式!切片概念!!菱形继承详解!)

继承 了解继承继承的定义基类和派生类对象赋值转换继承中的作用域派生类的默认成员函数继承和友元菱形继承和菱形虚拟继承 了解继承 继承机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保 持原有类特性的基础上进行扩展&#xff0c;增加功能&a…