零基础、大白话,Vue3全篇通俗疗法(上):基础知识【看得懂】

前言

        

        最近有个小朋友想了解Vue前端技术,但他只懂一些HTML基础,让我用最简单的方式讲解。于是就有了这篇面向初学者的博文。

        老手请绕行,本文专为新手准备。如果发现用词不当的地方欢迎留言指正,觉得对新手有帮助的话请收藏点赞。

基础

  • 什么是Vue

它是一个前端框架、目前最新版本是Vue3、本质上就是在单个页面上进行组件渲染。

  • 为什么是Vue

原因很多,但最重要的是生态好,学、用的人多;(参照来源各招聘平台对于前端的要求)

  • Vue 版本选择

作为技术,当然选择新版本了,但相对旧版本有一些变化,新版本同时支持组合式API与选项式API,目前官方推荐采用组合式API(用到什么就引用什么速度更快)

项目\版本

VUE2

VUE3

构建工具

Vue CLI

Vite

状态管理

VueX

Pinia

IDE 增强插件

Vetur

vue-official

静态生成

VuePress

VitePress

  • Vue 引擎选TS还是JS

JavaScript (JS):简单、广泛。TypeScript(TS):类型安全、更好的可维护性。同样都是要花精力学习的话还是推荐TS,尽管你学习了JS,还是建议你慢慢接受TS。

  • Vue Router

VUE Router 官言路由,用于跳转用;之前用MVC是用后端Controller层控制路由跳转,现在由前端控制。

  • Vue Panner

基于Vue3.0 状态管理工具

  • VitePress

静态网站成生器:VUE本质上就是在单个页面上组装拆解,所以它不利于SEO优化(换言之搜索引擎的网站爬不到),现在有了它就解决了这个问题。

  • 开发工具选择

这个因人而异、可以是VSCode(免费)、也可以是WebStorm(收费),以下是常见的工具对比。

类型/常用工具

VSCode

HBuilder

WebStrom

Trae

cursor

费用

免费

免费

收费

免费

免费

插件生态评分(个人)

95

60

95

80

80

智能化(个人)

80

60

70

90

90

  • 准备

在开发的电脑上必有安装好Node,推荐使用新版本。

  • 创建

npm init vue@3
npm init vue@3
Need to install the following packages:
create-vue@3.16.4
Ok to proceed? (y) y  //是否要创建版本为3.16.4 的VUE┌  Vue.js - The Progressive JavaScript Framework
│
◆  请输入项目名称:
│  demo█
  • 选择

Need to install the following packages:
create-vue@3.16.4
Ok to proceed? (y) y
┌  Vue.js - The Progressive JavaScript Framework
│
◇  请输入项目名称:
│  demo
│
◆  请选择要包含的功能: (↑/↓ 切换,空格选择,a 全选,回车确认)
│  ◻ TypeScript
│  ◻ JSX 支持
│  ◻ Router(单页面应用开发)
│  ◻ Pinia(状态管理)
│  ◻ Vitest(单元测试)
│  ◻ 端到端测试
│  ◻ ESLint(错误预防)
│  ◻ Prettier(代码格式化)
  • 目录

node_modules/ 存放NPM下载的依赖包
package.json 项目依赖配置文件
index.html VUE项目的入口文件
vite.config.ts vue的构建、打包配置文件
env.d.ts TypeScri环境变量,全局类型声明
public/ 静态资源目录
src/源码目录app.vue 应该主组件main.ts 应该入口文件,创建Vue实例与挂载assets/ 静态资源文件components/通常存放复用组件目录
main.css 全局样式文件
base.css 基础样式文件

项目运行流程

1.main.ts里声明一个VUE项目中的唯一一个实例

import './assets/main.css'import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

2.index.html 引用main.ts的实例,去挂载主组合app.vue

    <!DOCTYPE html>
    <html lang=""><head><meta charset="UTF-8"><link rel="icon" href="/favicon.ico"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vite App</title></head><body><div id="app"></div><script type="module" src="/src/main.ts"></script></body>
    </html>

    3.app.vue 总父组件去挂载各种子组件

      <!DOCTYPE html>
      <html lang=""><head><meta charset="UTF-8"><link rel="icon" href="/favicon.ico"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vite App</title></head><body><div id="app"></div><script type="module" src="/src/main.ts"></script></body>
      </html>

      VUE模板

      app.vue是主组件,以下相关功能演示都在这个组件中测试。

      一个完整Vue文件必须包含script与模板template,且忽略前后顺序(前后位置不影响)

      <script setup lang="ts">//数据业务处理层
      </script><template>//数据呈现
      </template>

      数据绑定渲染示例

      <script setup lang="ts">const msg = 'Hello World'
      </script><template><h1>{{ msg }}</h1>
      </template>

      组合式API

      选项式API网上教程太多了不再说明,我这里只对ts下的组合式API进行示例。

      <script setup lang="ts">
      // setup 相关于 选项式中的default....那一套,setup 函数  ;lang="ts" 告诉编译器,这个文件是ts文件//推荐使用ref()来定义响应式数据import {computed, onMounted, onUnmounted, ref, watch} from "vue";const msg=ref('这是一个消息');let msg2="这也是一个消息"//定义方法function changeMsg(){msg.value="这是修改后的消息";msg2="这也是修改后的消息";}//监听msg数据watch(msg, (newVal) => {alert(newVal);})watch(() => msg2, (newVal) => {alert(newVal);})// 计算属性const Isok = computed(() => {return msg.value === "这是一个消息" ? "这是一个消息" : "";});// 生命组件周期..........onMounted(() => {alert("组件已挂载");});onUnmounted(() => {alert("组件已卸载");});</script><template><div><h1>{{msg}}</h1><h1>{{msg2}}</h1><button @click="changeMsg">修改消息</button></div>
      </template>
      


      VUE的基本操作

      • 渲染 

              条件渲染

              

      <script setup lang="ts">const code='A';const isShow=true;
      </script><template><div ><!-- 条件渲染:if ---><h1 v-if="code  === 'A'">A</h1><h1 v-else-if="code  === 'B'">B</h1><h1 v-else>C</h1><!-- 条件渲染显示控制 ---><h1 v-show="isShow">isShow</h1></div></template>

              列表渲染

        可以将List和对象渲染出来,原理是:For循环方式处理

      <script setup lang="ts">const list  = [{id: 1,name: 'Todo 1',completed: false},{id: 2,name: 'Todo 2',completed: true},{id: 3,name: 'Todo 3',completed: false}];const obj={name:'test',age:18,sex:'男',height:1.8};
      </script><template><div ><li v-for="(item,index) in list" :key="item.id">{{index}} - {{ item.name }}</li><li v-for="(item,index) in obj" :key="index">{{ item }}</li></div></template>
      • 事件

              无参
      <script setup lang="ts">const showMessageWithParam = (message: string) => {alert(message);
      };</script><template><div ><button  @click="showMessageWithParam('TEST!')">点击我</button></div></template>
              有参   
      <script setup lang="ts">
      const msg="";
      const showMessageWithParam = (message: string) => {alert(message);
      };
      </script>
      <template><div ><input v-model="msg" placeholder="请输入内容" /><button @click="showMessageWithParam(msg)">传递输入内容</button></div>
      </template>
              Event处理    
      <script setup lang="ts">
      const list = ["1", "2", "3"];
      const showMessageWithParam = (e: Event, message: string) => {(e.target as HTMLButtonElement).innerHTML = "已点击";alert(message);
      };
      </script>
      <template><div ><li v-for="item in list" :key="item" @click="showMessageWithParam($event,item)">{{ item }}</li></div>
      </template>
              事件修饰

      对事件进行修饰以达到阻止事件或事件冒泡等问题

      <script setup lang="ts">
      const message = "hello world";
      const showMessageWithParam = (e: Event, message: string) => {(e.target as HTMLButtonElement).innerHTML = "已点击";alert(message);
      };
      </script>
      <template><div ><a href="https://www.baidu.com" @click.prevent="showMessageWithParam($event,message)">测试一下</a></div>
      </template>
      • 属性

              class

      在TS中定义一个变量去指向一个样式类,再模板中用这个定义的变量去渲染就实现了属性绑定;绑定方式以『:』+属性="定义变量的名"形式实现,如下所示。

      <script setup lang="ts">
      const classObj = 'test';
      const demoid=11;
      const msg = 'Hello World!';
      </script><template><div :class="classObj" :id="demoid.toString()">    <h1>{{ msg }}</h1></div></template><style scoped>
      .test {color: red;font-size: 50px;
      }
      </style>

      以上可以把一组绑定直接封装一个对象进行绑定

      <script setup lang="ts">
      const msg = 'Hello World!';
      const obj={class:'test',id:'abc'
      };
      </script><template><!-- 绑定对象 ---><div v-bind="obj"><h1>{{ msg }}</h1></div></template><style scoped>
      .test {color: red;font-size: 50px;
      }
      </style>

      以数组形式绑定

      <script setup lang="ts">
      const classObj = 'test';
      const demoid=11;
      const msg = 'Hello World!';
      const t1="test2";
      const t2="test3";
      </script><template><!--- 以对象形式绑定 --><div :class="classObj" :id="demoid.toString()"><h1>{{ msg }}</h1></div><!--- 以数组形式绑定 --><div :class="[t1,t2]"><h1>{{ msg }}</h1></div></template><style scoped>
      .test {color: red;font-size: 50px;
      }
      .test2{color: blue;
      }
      .test3{font-size: 30px;
      }
      </style>

              style

      以:style='类'进行绑定,也可以通过:style='[类1、类2]'以数组进行绑定

      <script setup lang="ts">
      const msg = 'Hello World!';
      const obj={color :'red',fontSize :'30px'
      };
      const ob2={backgroundColor :'yellow'
      };
      </script><template><!--- 以对象形式绑定 --><div :style="obj"><h1>{{ msg }}</h1></div><div :style="[obj,ob2]"><h1>{{ msg }}</h1></div>
      </template>
      • 数组

      方法

      解释

      push()

      向数组中添加数据

      pop()

      删除数组中的数据

      shift()

      删除第一个

      unshift()

      向数组中添加数据并放在第一位

      splice()

      splice(开始删除的位置, 数量(可选择), 删除的元素1(可选择), ..., 删除的元素N(可选择))

      sort()

      排序(升)

      reverse()

      反转数组

      concat()

      以替换数组形式添加数据

      filter()

      <script setup lang="ts">
      import { ref } from "vue";const newItem = ref("");
      const list = ref(["a", "b", "c"]); // 使用 ref 包裹 list 以保证响应性
      const addItem = () => {if (newItem.value.trim()) {list.value.push(newItem.value); // 向数组中添加数据newItem.value = "";}
      };
      const addItem2 = () => {if (newItem.value.trim()) {list.value = list.value.concat([newItem.value]);//以替换的方式添加到数组中newItem.value = "";}
      };
      </script><template><div><div><input v-model="newItem" placeholder="输入新项" /><button @click="addItem">添加</button><button @click="addItem2">添加2</button></div><ul><li v-for="item in list" :key="item">{{ item }}</li></ul></div>
      </template>
      • 侦听

      通过watch定义要监听的对象实现更多实用的功能

      <script setup lang="ts">
      import { ref,watch } from 'vue';
      const msg = ref('Hello World!');
      function changeMsg() {msg.value = 'Hello TONGYI Lingma!';
      }watch(() => msg.value,(newVal, oldVal) => {alert(`msg 从 ${oldVal} 变为 ${newVal}`);}
      );</script><template><!--- 以对象形式绑定 --><div ><h1>{{ msg }}</h1>  <button @click="changeMsg">change</button></div></template>
      • 计算属性

      为了解决复杂的计算,让代码具备一定的可维护性

      <script setup lang="ts">
      import { computed, ref } from "vue";const newItem = ref("");
      //  计算属性
      const Isok = computed(() => {return newItem.value === "ok" ? "ok" : "";
      });</script><template><div><div><input v-model="newItem" placeholder="输入新项" /><!---  计算属性 ---><p v-text="Isok"></p></div></div>
      </template>
      • 表单

      表单:v-mode="数据"可以对数据进行双向绑定

      <script setup lang="ts">
      import { ref } from 'vue';
      const msg = ref('Hello World!');
      function changeMsg() {msg.value = 'Hello TONGYI Lingma!';
      }
      </script><template><!--- 以对象形式绑定 --><div ><h1>{{ msg }}</h1></div><div><form><input type="text" v-model="msg"></input></form></div>
      </template>
      • DOM操作

      尽管不提倡直接操作DOM,也有时我们需要对DOM进行操作;通过refs的方式就能实现;

      <script setup lang="ts">
      import { ref, onMounted } from 'vue';
      const msg = ref('Hello World!');
      const testRef = ref<HTMLElement | null>(null);const sendMessage = () => {if (testRef.value) {testRef.value.innerHTML = '修改了!';}
      };
      </script><template><div ref="testRef"><h1>{{ msg }}</h1><button @click="sendMessage">操作</button></div>
      </template>

      组件

      • 生命周期

      组件类似于当年我在做CS程序的时候,窗口有创建事件、显示事件、关闭事件等,在相应的事件里写相应的代码;VUE也是同理,生命周期如下图所示。根据这些生命周期去处理相应周期的代码去实现相应的逻辑功能。

      <script setup lang="ts" xmlns="http://www.w3.org/1999/html">
      import {ref, onMounted, onUpdated, onUnmounted, onBeforeMount, onBeforeUnmount, onBeforeUpdate} from 'vue';const msg = ref('199991111');
      //组件创建前
      onBeforeMount(() => {console.log('组件创建前');
      })
      // 组件创建后示例
      onMounted(() => {console.log('组件创建后示例');
      })
      //组件挂载前
      onBeforeMount(() => {console.log('组件挂载前');
      })
      //组件挂载后
      onMounted(() => {console.log('组件挂载后');
      })
      //组件更新前
      onUpdated(() => {console.log('组件更新前');
      })
      //组件更新后
      onBeforeUpdate(() => {console.log('组件更新后');
      })
      //组件卸载前
      onBeforeUnmount(() => {console.log('组件卸载前');
      })
      //组件卸载后
      onUnmounted(() => {console.log('组件卸载后');
      })</script>
      <template></template>
      • 构成部分

              前面讲过VUE 本质上就是在一个HTML不断的组拆,而APP.VUE文件是一个入口文件,所以每一个vue文件视作一个组件。

              组件包含必要的<template>负责数据呈现 、<script> 业务逻辑处理(如无逻辑与数据可以不包含)、样式<style>部分(如无样式或默认总样式可以不包含。

      <script setup lang="ts"></script><template></template><style scoped></style>
      • 引用

      定义的组件:test.vue

      <script setup lang="ts">const msg='测试一下';
      </script>
      <template><div><h1>{{msg}}</h1></div>
      </template>

      调用组件:app.vue

      <script setup lang="ts">import Test from '@/com/test.vue'
      </script><template><Test/>
      </template>
      • 嵌套

      下面是一个关系图:

      人(app.vue)-头(head.vue)-中部(mind.vue)-左手(leftHand.vue)-胸(chest.vue)-右手(rightHand.vue)-下部(boot.vue)-左腿(leftLeg)-右腿(rightLeg)

      接下来我将用代码进行实现

      head.vue:头部代码

      <template><div><h1>------头部-------</h1></div>
      </template>

      leftHand.vue:左手

      <template><div><h1>左手</h1></div>
      </template>

      chest.vue:胸

      <template><div><h1>这是胸部</h1></div>
      </template>

      rightHand.vue:右手

      <template><div><h1>右手</h1></div>
      </template>

      mind.vue:中部

      <script setup lang="ts">
      import LeftHand from "@/com/leftHand.vue";
      import Chest from "@/com/chest.vue";
      import RightHand from "@/com/rightHand.vue";
      </script><template><div><h1>-----中部-------</h1><LeftHand /><Chest /><RightHand /></div>
      </template>

      leftLeg.vue:左腿

      <template><div><h1>左腿</h1></div>
      </template>

      rightLeg.vue:右腿

      <template><div><h1>右腿</h1></div>
      </template>

      boot.vue:下部

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";
      </script>
      <template><h1>---下部------</h1><LeftLeg /><RightLeg />
      </template>

      app.vue:整体

      <script setup lang="ts">import Head from "@/com/head.vue";import Mind from "@/com/mind.vue";import Boot from "@/com/boot.vue";
      </script><template><div><Head/><Mind/><Boot/></div></template>
      • 全局注册

              以上是做了个示例,如果你想不引用,实现处理调用那就要配置相应组为全局组件,那需要在main.ts里声明组件。以下是把test.vue注册为全局,然后用app.vue直接调用。

              ps:非必要不提供注册全局组件

      main.ts

      import './assets/main.css'import { createApp } from 'vue'
      import App from './App.vue'
      import Test from "@/com/test.vue";createApp(App).mount('#app')

      app.vue

      <script setup lang="ts">import Head from "@/com/head.vue";import Mind from "@/com/mind.vue";import Boot from "@/com/boot.vue";import Test from "@/com/test.vue";
      </script><template><div><test/><Head/><Mind/><Boot/></div></template>
      • 传值

      父传子
      方案1:props 逐级传值

      在父组件上调用子组件以:传递名="数据"的形式进行传值;在子组件上的props上用传递名接收,且接收到的数据无法被修改。

      父组件

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";
      import {ref} from "vue";// 自定义事件函数
      const handleCustomEvent = (data :any) => {msgFormLeft.value  = data;
      };
      const msgFormLeft=ref('空');
      const test2="test2";
      const test3={name : "test3",age : 18,
      }
      </script><template><!--- 只用test传数据 test2传绑定数据  test3传对象---><LeftLeg test="msg" :test2="test2" :test3="test3"/><a>{{msgFormLeft}}</a><RightLeg />
      </template>

      子组件

      <script setup lang="ts">
      import { defineEmits, ref, watch } from 'vue';// 定义 props 接收父组件传递的 PMSG 参数
      const props = defineProps({test: {type: String,required: true},test2: {type: String},test3: {type: Object,default: () => ({ name: '', age: 0 })}
      });// 将 PMSG 参数赋值给 msg
      const msg = ref(props.test);</script>
      <template><div><h1>左腿</h1><a>{{ msg }}</a><a>{{ test2 }}</a><a>{{ test3.name }}</a><a>{{ test3.age }}</a></div>
      </template> 
      方案2:依赖注入

      上面的方案虽然可以解决父传子,但很多项目是组件间层层嵌套。想像一下如果通过上述方式传值不仅代码量变大,而且可维护性也差。那么通过依赖注入的方式就可以实现父组件直传到基于父组件下的任何一个组件中。

      首先provide在父组件中定义,子组件中用inject接收就可以了。

      app.vue

      <script setup lang="ts">import Boot from "@/com/boot.vue";import {provide} from "vue";
      const myValue = "Hello from provide/inject";
      const obj={name: 'John',age: 30
      };
      provide('myKey', myValue);
      provide('myObj', obj);
      </script><template><div><Boot/></div></template>

      子子组件rightLeg.vue

      <script setup lang="ts">
      import {inject} from "vue";
      const msg = inject<string>("myKey");
      const obj = inject<{ name: string, age: number}>("myObj");
      </script>
      <template><div><h1>右腿</h1><hr><h1> {{ inject<string>("myKey") }} </h1><hr><h1>{{ msg }}</h1><hr><h1>{{ obj?.name }}</h1><hr><h1>{{ obj?.age }}</h1></div>
      </template>

      子传父
              方案1:自定义事件传递
      1. 子组件里定义一个方法

      2. 在子组排方法里以emit('标识')的方式命名一个标识

      3. 父组件里在调用子组件那里用@标识名绑定个这标识并在后面对应父组件对应的事件

              无参

              子组件

              

      <script setup lang="ts">import { defineEmits } from 'vue';const emit = defineEmits(['fTest']);const test = () => {emit('fTest');}
      </script>
      <template><div><h1>左腿</h1><button @click="test">回传调用父组件</button></div>
      </template>

              父组件

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";// 自定义事件函数
      const handleCustomEvent = () => {alert("来自子数据的调用")
      };
      </script><template><LeftLeg @fTest="handleCustomEvent"/><RightLeg />
      </template>

              有参        

              子组件

      <script setup lang="ts">import { defineEmits } from 'vue';const emit = defineEmits(['fTest']);const test = () => {emit('fTest',  '左腿');}
      </script>
      <template><div><h1>左腿</h1><button @click="test">回传调用父组件</button></div>
      </template>

              父组件

              

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";// 自定义事件函数
      const handleCustomEvent = (data :any) => {alert(data)
      };
      </script><template><LeftLeg @fTest="handleCustomEvent"/><RightLeg />
      </template>

              时时传

              子组件

      <script setup lang="ts">
      import { defineEmits, ref, watch } from 'vue';const emit = defineEmits(['fTest']);
      const msg = ref('');const test = () => {emit('fTest', msg.value);
      };watch(msg, (newVal) => {// 当msg值发生变化时执行test方法test();
      });
      </script>
      <template><div><h1>左腿</h1><input type="text" v-model="msg" @change="test"></div>
      </template>

              父组件

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";
      import {ref} from "vue";// 自定义事件函数
      const handleCustomEvent = (data :any) => {msgFormLeft.value  = data;
      };
      const msgFormLeft=ref('空');
      </script><template><LeftLeg @fTest="handleCustomEvent"/><a>{{msgFormLeft}}</a><RightLeg />
      </template>
              方案2:利用props传事件实现

      父组件

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";
      import {ref} from "vue";
      // 自定义事件函数
      const handleCustomEvent = (data :any) => {msgFormLeft.value  = data;
      };
      const msgFormLeft=ref('空');
      </script><template><!--- 只用test传数据 test2传绑定数据  test3传对象---><LeftLeg test="msg" :handleCustomEvent="handleCustomEvent"/><a>{{msgFormLeft}}</a><RightLeg />
      </template>

      子组件

      <script setup lang="ts">
      import { ref, watch } from 'vue';
      const props = defineProps({handleCustomEvent: {type: Function,required: true}
      });
      const msg = ref('');watch(() => msg.value, (newValue, oldValue) => {props.handleCustomEvent(newValue)
      });
      // 如果需要在子组件中直接调用父组件函数,可以通过以下方式:
      // 例如:props.handleCustomEvent('aaaaaaaaa');
      </script>
      <template><div><h1>左腿</h1><input type="text" v-model="msg"></div>
      </template>
      • 插槽

      以<slot>为标签显示,把带有引用的子组件内容块显示

      直接插

      父组件

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";
      import { ref } from "vue";const msgFormLeft = ref('空1111111');</script><template><LeftLeg><!-- 插槽A用于传递父组件的固定内容 --><div><h2>这是传过来的内容</h2></div></LeftLeg><RightLeg />
      </template>

      子组件

      <script setup lang="ts" xmlns="http://www.w3.org/1999/html">
      import { ref, watch } from 'vue';const msg = ref('');</script>
      <template><div><h1>左腿</h1><slot ></slot><hr/></div>
      </template>
      插进去带数

       父组件

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";
      import { ref } from "vue";const msgFormLeft = ref('空1111111');</script><template><LeftLeg><!-- 插槽A用于传递父组件的固定内容 --><div><a>{{ msgFormLeft }}</a></div></LeftLeg><RightLeg />
      </template>

      子组件

      <script setup lang="ts" xmlns="http://www.w3.org/1999/html">
      import { ref, watch } from 'vue';const msg = ref('');</script>
      <template><div><h1>左腿</h1><slot ></slot><hr/></div>
      </template>

      一次插入多个,分别显示

       父组件

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";
      import { ref } from "vue";const msgFormLeft = ref('空1111111');</script><template><LeftLeg><!-- 插槽A用于传递父组件的固定内容 --><template #A><div><h2>这是传过来的内容</h2></div></template><!-- 插槽B用于传递父组件的数据内容 --><template #B><div><a>{{ msgFormLeft }}</a></div></template></LeftLeg><RightLeg />
      </template>

      子组件

      <script setup lang="ts" xmlns="http://www.w3.org/1999/html">
      import { ref, watch } from 'vue';const msg = ref('');</script>
      <template><div><h1>左腿</h1><slot name="A"></slot><hr/><slot name="B"></slot><hr/></div>
      </template>

      插进去的数据混合父数据与子数据

      子组件

      <script setup lang="ts" xmlns="http://www.w3.org/1999/html">
      import { ref, watch } from 'vue';const msg = ref('199991111');</script>
      <template><div><h1>左腿</h1><slot name="A"></slot><hr/><slot name="B"></slot><hr/><slot name="C" :msg="msg"></slot><hr/></div>
      </template>

       父组件

      <script setup lang="ts">
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";
      import { ref } from "vue";const msgFormLeft = ref('空1111111');</script><template><LeftLeg><!-- 插槽A用于传递父组件的固定内容 --><template #A><div><h2>这是传过来的内容</h2></div></template><!-- 插槽B用于传递父组件的数据内容 --><template #B><div><a>{{ msgFormLeft }}</a></div></template><!-- 插槽C用于接收来自子组件的消息 --><template #C="{ msg }"><div><p>来自子组件的消息: {{ msg || '暂无消息' }}</p></div></template></LeftLeg><RightLeg />
      </template>
      • 动态组件

      我们大多数情况下不可能把所有组件都呈现在父组件中,而是希望动态实现它。

      这时我们只需要通过<component :is="组件名或者动态数据中的组件名">就能实现;

      基本动态组件
      <script setup lang="ts">
      import { ref } from "vue";
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";// 定义当前激活的组件名称,类型为组件对象的键,初始值为 "LeftLeg"
      const tabComponent = ref<keyof typeof components>("LeftLeg");// 组件对象,包含 LeftLeg 和 RightLeg 两个组件,并通过 as const 确保其键值不可变
      const components = {LeftLeg,RightLeg
      } as const;// 切换组件函数,接收当前组件名称作为参数,切换为另一个组件
      const switchComponent = (componentName: "LeftLeg" | "RightLeg") => {// 如果当前是 LeftLeg,则切换为 RightLeg,反之亦然tabComponent.value = componentName === "LeftLeg" ? "RightLeg" : "LeftLeg";
      };</script><template><!-- 使用动态组件并确保正确绑定 --><component :is="components[tabComponent]" /><button @click="switchComponent(tabComponent)">切换</button></template>
      动态组件驻留

      以上组件每次加载都会完成一次初始化会让对应页面的数据还原,此时在外部增加keep-alive组件包含一下就可以了

      父组件

      父组件

      <script setup lang="ts">
      import { ref } from "vue";
      import LeftLeg from "@/com/leftLeg.vue";
      import RightLeg from "@/com/rightLeg.vue";// 定义当前激活的组件名称,类型为组件对象的键,初始值为 "LeftLeg"
      const tabComponent = ref<keyof typeof components>("LeftLeg");// 组件对象,包含 LeftLeg 和 RightLeg 两个组件,并通过 as const 确保其键值不可变
      const components = {LeftLeg,RightLeg
      } as const;// 切换组件函数,接收当前组件名称作为参数,切换为另一个组件
      const switchComponent = (componentName: "LeftLeg" | "RightLeg") => {// 如果当前是 LeftLeg,则切换为 RightLeg,反之亦然tabComponent.value = componentName === "LeftLeg" ? "RightLeg" : "LeftLeg";
      };</script><template><!-- 使用动态组件并确保正确绑定 --><keep-alive><component :is="components[tabComponent]" /></keep-alive><button @click="switchComponent(tabComponent)">切换</button></template>

      子组件

      <script setup lang="ts">
      import { ref } from "vue";const tttt = ref("左腿");function updateMsg(newMsg: string) {tttt.value = newMsg;
      }
      </script><template><h1>{{ tttt }}</h1><button @click="updateMsg('1111111')">更新</button>
      </template>
      动态组件懒加载

      动态组件时会一次性把组件所有组件进行渲染,而用到什么就渲染什么其实才科学。

      <script setup lang="ts">
      import {defineAsyncComponent, ref} from "vue";
      // 异步组件
      const LeftLeg = defineAsyncComponent(() => import("@/com/leftLeg.vue"));
      const RightLeg = defineAsyncComponent(() => import("@/com/rightLeg.vue"));// 定义当前激活的组件名称,类型为组件对象的键,初始值为 "LeftLeg"
      const tabComponent = ref<keyof typeof components>("LeftLeg");// 组件对象,包含 LeftLeg 和 RightLeg 两个组件,并通过 as const 确保其键值不可变
      const components = {LeftLeg,RightLeg
      } as const;// 切换组件函数,接收当前组件名称作为参数,切换为另一个组件
      const switchComponent = (componentName: "LeftLeg" | "RightLeg") => {// 如果当前是 LeftLeg,则切换为 RightLeg,反之亦然tabComponent.value = componentName === "LeftLeg" ? "RightLeg" : "LeftLeg";
      };</script><template><!-- 使用动态组件并确保正确绑定 --><keep-alive><component :is="components[tabComponent]" /></keep-alive><button @click="switchComponent(tabComponent)">切换</button></template>

      指令

      所谓指令是指操作DOM元素的命令,VUE有内置的v-if、v-show就是指令;

      自定义指令

      • 以变量形式以对象方式出现,具有固定的生命周期

      • 变量名命名以驼峰方式进行命令。

      • 使用则驼峰以'-'拆分且全部小写。

      示例

      <script setup lang="ts">
      import LeftHand from "@/com/leftHand.vue";
      import Chest from "@/com/chest.vue";
      import RightHand from "@/com/rightHand.vue";
      const vTest={create:()=>{console.log("创建")},mounted:()=>{console.log("挂载")},unmounted:()=>{console.log("卸载")},beforeUpdate:()=>{console.log("更新前")},updated:()=>{console.log("更新")},update:() => {console.log("更新")},beforeUnmount:()=>{console.log("卸载前")}
      }
      </script><template><div><!-- 测试 --><h1 v-test>-----中部-------</h1>
      <!--    <LeftHand />-->
      <!--    <Chest />-->
      <!--    <RightHand />--></div>
      </template>

      相应的周期函数都包含el对象,利用el对象可以实现具体的功能。

      <script setup lang="ts">
      import LeftHand from "@/com/leftHand.vue";
      import Chest from "@/com/chest.vue";
      import RightHand from "@/com/rightHand.vue";
      const vTest = {created() {console.log("创建");},mounted(element, binding, vnode) {element.innerHTML=element.innerHTML+"众纳原创";},unmounted() {console.log("卸载");},beforeUpdate() {console.log("更新前");},updated() {console.log("更新");},beforeUnmount() {console.log("卸载前");}
      };
      </script><template><div><!-- 测试 --><h1 v-test>-----中部-------</h1>
      <!--    <LeftHand />-->
      <!--    <Chest />-->
      <!--    <RightHand />--></div>
      </template>

      以上定义的指令都是局部指令,如果想整体项目都要用到需要到main.ts里进行定义

      import './assets/main.css'import { createApp } from 'vue'
      import App from './App.vue'
      const app = createApp(App)
      app.directive('focus', {mounted(element) {element.style.color='red';element.style.fontSize='90px';}
      })
      app.mount('#app')

      使用时则以v-"定义的名称"进行绑定使用

      ```typescript
      import './assets/main.css'import { createApp } from 'vue'
      import App from './App.vue'
      const app = createApp(App)
      app.directive('focus', {mounted(element) {element.style.color='red';element.style.fontSize='90px';}
      })
      app.mount('#app')
      ```> 使用时则以v-"定义的名称"进行绑定使用```html
      <script setup lang="ts">
      import LeftHand from "@/com/leftHand.vue";
      import Chest from "@/com/chest.vue";
      import RightHand from "@/com/rightHand.vue";
      const vTest = {created() {console.log("创建");},mounted(element, binding, vnode) {element.innerHTML=element.innerHTML+"众纳原创";},unmounted() {console.log("卸载");},beforeUpdate() {console.log("更新前");},updated() {console.log("更新");},beforeUnmount() {console.log("卸载前");}
      };
      </script><template><div><!-- 测试 --><h1 v-test v-focus>-----中部-------</h1>
      <!--    <LeftHand />-->
      <!--    <Chest />-->
      <!--    <RightHand />--></div>
      </template>
      ```
      

      本篇完成 ,下篇会涉及路由、状态管理、Axios通信、Element UI等扩展知识,请关注博主,第一时间获取高品质的技术文章。

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

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

      相关文章

      JavaScript性能优化实战

      JavaScript性能优化实战技术文章大纲 性能优化的重要性 解释为什么性能优化对用户体验和业务指标至关重要讨论核心Web指标&#xff08;LCP、FID、CLS&#xff09;与JavaScript性能的关系 代码层面优化 减少DOM操作&#xff0c;使用文档片段或虚拟DOM避免频繁的重绘和回流&a…

      考研英语作文评分标准专业批改

      考研英语作文专业批改经过官方评分标准严格对标&#xff0c;彻底改变你的作文提升方式&#xff0c;打开 懂试帝小程序 直达批改。 &#x1f3af; 批改服务核心优势 ✨ 官方标准严格对标 完全按照考研英语官方五档评分制&#xff0c;从内容完整性、组织连贯性、语言多样性到语…

      智能群跃小助手发布说明

      1.初次登陆需要授权码 2.社群维护页面 3.产品营销页面

      SAM2论文解读-既实现了视频的分割一切,又比图像的分割一切SAM更快更好

      code&#xff1a;https://github.com/facebookresearch/sam2/tree/main demo:https://sam2.metademolab.com/ paper:https://ai.meta.com/research/publications/sam-2-segment-anything-in-images-and-videos/ 这是SAM 这是SAM2 Facebook出品&#xff0c;继SAM在图像上分割…

      WPF 的RenderTransform使图标旋转180°

      只是记录一下思想&#xff1a; 本来想找两个对称的图标给按钮用&#xff0c;但是另一个找不到&#xff0c;就想到可不可以旋转180实现另一个图标的效果&#xff0c;问了一下DeepSeek&#xff1a; <Path Width"30" Height"30" Margin"1"Data…

      Matplotlib 绘图库使用技巧介绍

      目录 前言 Matplotlib 简介 快速入门 图形结构解剖 常用绘图函数 子图与布局 单行多列子图&#xff1a; 网格布局&#xff1a; 自定义位置&#xff1a; 样式与标注 中文字体与科学计数 图例、网格、坐标轴 动态图与动画 三维绘图 常见问题与技巧 前言 Matplotli…

      【Java基础算法】1.相向指针练习

      📘博客主页:程序员葵安 🫶感谢大家点赞👍🏻收藏⭐评论✍🏻 一、两数之和 Ⅱ(167) 1.1 题目介绍 给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 nu…

      “开放原子园区行”太原站:openKylin以开源之力,赋能产业发展

      在数字化与智能化浪潮驱动下&#xff0c;开源技术已成为全球科技创新与产业升级的核心引擎&#xff0c;并为培育新质生产力开辟关键路径。为加速开源生态建设&#xff0c;赋能区域经济高质量发展&#xff0c;由开放原子开源基金会、山西省工业和信息化厅、山西转型综合改革示范…

      【Elasticsearch】自定义相似性算法

      在 Elasticsearch 中&#xff0c;可以通过自定义相似度算法来优化搜索结果的相关性。以下是几种常见的自定义相似度算法的方法&#xff1a; 1. 使用内置相似度算法 Elasticsearch 默认使用 BM25 算法&#xff0c;但也可以切换到其他内置的相似度算法&#xff0c;如 TF-IDF 或布…

      【对比】DeepAR 和 N-Beats

      1. DeepAR 1.1 核心思想 提出者&#xff1a;亚马逊&#xff08;Amazon&#xff09;团队于2018年提出。目标&#xff1a;针对多变量时间序列进行概率预测&#xff08;Probabilistic Forecasting&#xff09;&#xff0c;输出预测值的分布&#xff08;如均值、方差、置信区间&a…

      Spring Boot单元测试终极指南:从环境搭建到分层测试实战

      Spring Boot测试终极指南&#xff1a;从环境搭建到分层测试实战 掌握MockMvc与分层测试策略&#xff0c;让你的代码质量提升一个维度 一、环境搭建&#xff1a;Maven依赖深度解析 Spring Boot测试的核心依赖在pom.xml中配置如下&#xff1a; <dependencies><!-- 核心…

      卷积类型总结

      1. 标准卷积 (Convolution) 原理&#xff1a; 一个包含 K 个滤波器的卷积层&#xff08;每个滤波器大小为 FxF x C_in&#xff09;在输入特征图上滑动。在每个位置&#xff0c;滤波器与输入图像的局部区域进行逐元素相乘再求和&#xff08;点积运算&#xff09;&#xff0c;得到…

      HP iLO使用实例:Integrated Lights-Out

      文章目录 参考名词解释iLODMTF SMASH CLP命令HP提供的命令VSPBIOS启动顺序BIOS指令启动时报的电源错误如果ilo登陆不上去参考 ilo命令 https://support.hpe.com/hpesc/public/docDisplay?docId=c03334058 名词解释 iLO 从字面理解:Integrated Lights-Out,就是整合灯出;…

      【前端隐蔽 Bug 深度剖析:SVG 组件复用中的 ID 冲突陷阱】

      前端隐蔽 Bug 深度剖析&#xff1a;SVG 组件复用中的 ID 冲突陷阱 创建时间: 2025/6/20 类型: &#x1f50d; Bug 深度分析 难度: ⭐⭐⭐⭐⭐ 高级 关键词: SVG、ID 冲突、Vue 组件、隐蔽 Bug、技术分析 &#x1f4d6; 引言 在前端开发的世界里&#xff0c;有一类 Bug 特别令…

      IDEA 中 Tomcat 部署 Java Web 项目(Maven 多模块 非 Maven 通用版)

      引言 Java Web 开发中&#xff0c;Tomcat 是最常用的 Servlet 容器&#xff0c;而项目类型通常分为 Maven 管理&#xff08;依赖自动处理、多模块聚合&#xff09; 和 非 Maven 纯手工管理&#xff08;手动引入 jar 包、配置项目结构&#xff09;。本文覆盖 两种项目类型 的 T…

      当建筑学会“行走”:MiC建筑如何重塑医疗空间

      当塔吊林立的工地被智能化工厂取代&#xff0c;当混凝土现浇的轰鸣被精密模块的无声拼接覆盖&#xff0c;建筑行业正经历着自钢筋混凝土革命以来最深刻的范式转移。模块化集成建筑&#xff08;MiC&#xff09;技术&#xff0c;这场以“制造组装”为核心的新型工业化浪潮&#x…

      计算机网络八股第二期

      计算机网络八股第二期 1.讲一讲从输入网址到网页显示之间发生了什么&#xff08;从网络的角度&#xff09; 想想一下你从网店买一本书&#xff0c;从输入网址到网页显示其实和你从网店买一本书差不多&#xff0c;网店发给你的是实体而网络传输的是文字&#xff0c;图片等等资…

      FPGA基础 -- Verilog 的值变转储文件(VCD:Value Change Dump)

      Verilog 的“值变转储文件&#xff08;VCD&#xff1a;Value Change Dump&#xff09;”&#xff0c;这是一项在仿真调试中至关重要的技术&#xff0c;可以帮助你“看见”RTL中每个信号随时间的变化过程。 一、什么是 Verilog 的值变转储文件&#xff08;VCD&#xff09; VCD …

      流水灯芯片74HC138 → 74HC164 → 74HC595核心功能、引脚作用及芯片定位

      一、74HC138&#xff1a;精准的“8选1开关” 核心作用 用3根控制线&#xff08;A0-A2&#xff09;实现8路严格单选&#xff0c;同一时刻仅1路输出低电平&#xff08;其他7路高电平&#xff09;。 &#x1f4cc; 本质&#xff1a;二进制地址译码器&#xff0c;不是数据寄存器。…

      鸿蒙Next仓颉语言开发实战教程:懒加载

      今天要分享的是仓颉开发语言中的懒加载。 先和初学者朋友们解释一下什么是懒加载。懒加载在代码中叫做LazyForEach&#xff0c;看到名字你一定能猜到它和ForEach的功能类似。只不过和ForEach的一次性加载所有数据不同&#xff0c;懒加载会根据屏幕可使区域按需加载数据&#x…