零基础Vue入门4——Vue3基础核心

本节重点:

  • vue3最佳实践

  • ref

  • reactive

  • computed

  • watch、watchEffect

讲解重点之后下面会带大家开发一个页面(表单+表格),之后会有一个TodoList的小练习,文末附有小练习的代码参考。跟着练习一定带你可以上手开发vue项目

我在gitcode上也建了了对应的vue学习项目,会跟随我的专栏进行定期代码更新,欢迎克隆下载GitCode - 全球开发者的开源社区,开源代码托管平台


响应式基础

vue3最佳实践

  • 单文件组件(即 *.vue 文件)

  • 组合式API+TypeScript

注:组合式API一般都会配合<script setup>语法使用,<script setup>是在单文件组件中使用组合式API的编译时语法糖(setup了解)。

<script setup> VS <script>

  1. 更少的样板内容,更简洁的代码。
  2. 能够使用纯 TypeScript 声明 props 和自定义事件。
  3. 更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象)。
  4. 更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)

Vue3写法最佳实践:单文件组件+ 组合式API+<script setup>语法糖+TypeScript

演练场

API

组合式API

Composition API是V3和V2.7的内置功能,具体是指一系列API的集合,可以使用函数的方式书写vue组件它包括如下api:

  • 响应式API(ref、reactive等)

  • 生命周期钩子(onMounted、onUnmounted等)

  • 依赖注入(provide、inject)

响应式基础

ref

ref 函数用来创建响应式的数据。它接收一个参数,并返回一个包含该参数的响应式数据。

使用场景——

  1. 可以使用ref()方法创建一个任何值类型的响应式。它将传入的参数包装成一个带.value属性的ref对象。声明Object类型时内部通过reactive来转为代理对象。

  2. ref能创造一种对任意值的“引用”,并且不丢失响应性。

注意:

  1. 可以被复写、赋值给某一个局部变量,解构或者被传入函数时,不会丢失响应性。
  2. 模板中调用ref,不需要添加.value
<!-- 页面功能 -->
<template>
  <div class="zk_box">
    <H3> 响应式对象被赋值给另一个本地变量时,本地变量调整不会影响响应式变量</H3>
    <p>Count: {
  
  { count.name }}</p>
    <button @click="increment">Increment</button>
    <button @click="externalIncrement">externalIncrement</button>
    <br/>
    <p>Count: {
  
  { countObj.name }}</p>
    <button @click="increment1">Increment1</button>
    <button @click="externalIncrement1">externalIncrement</button>
  </div>
</template>

<script setup>
import {ref, reactive} from 'vue';

const count = ref({
  name: 0
});

const increment = () => {
  count.value.name++; // 增加计数器的值
};

const externalIncrement = () => {
  let oldValue = count;
  oldValue.value = {
    name: 100
  }
};

const countObj = reactive({
  name: 0
})

const increment1 = () => {
  countObj.name++; // 增加计数器的值
};
const externalIncrement1 = () => {
  let oldValue = countObj;
  oldValue = {
    name: 100
  }
}

</script>

<style scoped>
.zk_box{
  width: 80%;
  height: 80%;
  margin: 0 auto;
  padding: 20px;
  background-color: #f5f5f5;
}
</style>

reactive

reactive 函数用来创建响应式的数据。它接收一个参数,并返回一个包含该参数的响应式数据。

使用场景——

  1. 可以使用reactive() 函数创建一个响应式对象或数组。

  2. reactive仅对对象类型有效(对象、数组、Map、Set),原始类型(string、number、boolean)无效。

注意:

  1. 不可用随意“替换”(复写)一个响应式对象,会导致对于初始应用的响应性连接丢失。
  2. 将响应式变量解构,之后修改值,不会影响原始响应式变量。
const state = reactive({ count: 0 })

// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++

由于reactive的部分局限性,官方建议:使用 ref() 作为声明响应式状态的主要 API


computed

computed 函数用来创建计算属性。它接收一个参数,并返回一个包含该参数的响应式数据。

使用场景——

  1. 常用于计算衍生值。 默认是只读的。 return返回的是一个计算属性ref,其他方法中可通过.value取值。

注意:

  1. 计算属性只做计算,不要在此处做异步请求或者更新DOM
<template>
  <p>{
  
  {bookObj.author}}:是否写过书?</p>
  <span>{
  
  {hasBook}}</span>
</template>

<script setup>
  import{ reactive,computed}from 'vue'
  const bookObj = reactive({
    author:'张爱玲',
    age:'40',
    books:['book1','book2','book3']
  });

  // 定义一个计算属性
  const hasBook = computed(()=>{
    return bookObj.books.length > 0 ? 'Yes':'No'
  })
   
</script>

watch 和 watchEffect

侦听器,跟踪某一个值或者多个值的变化之后处理某种操作。

使用场景——

计算属性不能做的事,可以通过侦听器进行,例如根据异步操作的结果修改另一个值。

  1. watch 函数用来监听响应式数据的变化。它接收两个参数,并返回一个包含该参数的响应式数据。第一个参数可以是ref、响应式对象、getter函数、或者数组。

    1. immediate :是否在侦听器创建时立即执行回调函数

    2. deep :是否深度监听

  2. watchEffect 立即执行且会自动跟踪回调的响应式依赖。主要应用有多了依赖项的侦听器,不需要传递监听源。

watch

watchEffect

  • 懒执行,数据发生变化时才会触发

  • 既要指明监视的属性,也要指明监视的回调

  • 在创建侦听器时,立即执行一遍回调

  • 不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性

<template>
  <button @click="handleIdChange">{
  
  {todoId}}</button>
  <button @click="reset">重置</button>
  <div>
    data:{
  
  {data}}
  </div>
</template>
<script setup>
import { ref, watch, watchEffect } from 'vue'
const todoId = ref(1)
const data = ref(null);

const handleIdChange = ()=>{
  todoId.value++ ;
}

const reset = ()=>{
  todoId.value = 1;
}

 // 下面2个监听是等效的 
watch(
    todoId,
    async () => {
      const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
      )
      data.value = await response.json();
      console.log(data.value);
    }, {
      immediate: true
    }
)

  
watchEffect(async () => {
  const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
  )
  data.value = await response.json()
})
</script>

依赖注入

  • provide()

  • inject()

provide() 提供一个值,可以被后代组件注入。 主要为解决props只能逐级透传的问题。父组件作为所有子组件的依赖提供者,后续所有的后代组件都可以使用

  • 之前

  • 现在

<script setup>
import { ref, provide } from 'vue'


// 提供响应式的值
const count = ref(0)
provide('count', count)


const location = ref('North Pole')
function updateLocation() {
  location.value = 'South Pole'
}
provide('location', {
  location,
  updateLocation
})

</script>
<!-- 在注入方组件 -->
<script setup>
  import { inject } from 'vue'

  const { location, updateLocation } = inject('location');
  const count = inject('count');
</script>

<template>
  <button @click="updateLocation">{
  
  { location }}</button>
  <div>{
  
  {count}}</div>
</template>

总结

  • setup 语法糖帮助更简洁地写代码,减少代码量。

  • ref 和 reactive 声明响应式数据,ref 可以创建任意值类型的响应式数据,使用需要添加.value,reactive 只能创建对象类型和数组类型的响应式数据。

  • computed、watch和watchEffect用于衍生数据的计算和数据侦听 。watchEffect 不需要指明监听的属性,它会在回调中用到哪个属性,就监听哪个属性。

  • provide 和 inject 用于依赖注入,解决组件层级过深传递数据的问题。

实战

结合之前准备阶段安装的demo项目,开发一个t表单+表格的页面功能。UI框架使用的是ant design vue。

准备阶段demo项目安装参考链接——零基础Vue学习1——Vue学习前环境准备-CSDN博客。

执行如下命令安装UI框架依赖:

  • antdv安装

pnpm i --save ant-design-vue@4.x

  • 修改main.ts

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/reset.css';

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(createPinia())
app.use(router)
app.use(Antd)

app.mount('#app')

先带大家写一个简单的页面结构:表单+表格,效果如下:

使用antdv的组件实现

1、本地新建一个模拟数据的文件,demoData.ts

// 表格数据
// 生成随机数据
const buildData = (size) => {
    let data = [];
    for (let i = 0; i < size; i++) {
        data.push({
            key: i,
            name: `张小${i}`,
            sex: Math.random() > 0.5 ? '男' : '女',
            age: Math.floor(Math.random() * 30),
            address: `西湖区湖底公园 ${i} 号`,
        });
    }
    return data;
}


export const tableData = buildData(20);
export const tableColumn = [
    {
        title: '姓名',
        dataIndex: 'name',
        key: 'name',
    },
    {
        title: '性别',
        dataIndex: 'sex',
        key: 'sex',
    },
    {
        title: '年龄',
        dataIndex: 'age',
        key: 'age',
    },
    {
        title: '住址',
        dataIndex: 'address',
        key: 'address',
    },
];

2、在App.vue文件中导入demoData文件

<template>
  <a-form ref="formRef" :model="formData" layout="inline">
    <a-form-item label="名称" name="name">
      <a-input v-model:value="formData.name" placeholder="请输入名称"/>
    </a-form-item>
    <a-form-item label="性别" name="sex">
      <a-select style="width:120px;" v-model:value="formData.sex" placeholder="请选择性别">
        <a-select-option v-for="item in sexList" :value="item">{
  
  { item }}</a-select-option>
      </a-select>
    </a-form-item>
    <a-form-item>
      <a-space>
        <a-button type="primary" @click="query">查询</a-button>
        <a-button @click="reset">重置</a-button>
      </a-space>
    </a-form-item>
  </a-form>
  <h1> {
  
  { title }}</h1>
  <a-table :columns="columns" :data-source="tableDataSource">
  </a-table>
</template>

<script setup>
import {ref, reactive, watch, computed, onMounted} from 'vue'
import {tableColumn, tableData} from "./views/demoData.ts"  // 模拟数据

// 表单数据
const formData = reactive({
  name: '',
  sex: ''
})

// 表格数据
const columns = tableColumn;
const tableDataSource = ref([])
const title = computed(() => {
  return `共计${tableDataSource.value.length}条`
})

// 性别列表
const sexList = ref([])
const getSexList = () => {
  sexList.value = ['男', '女'];
  formData.sex = sexList.value[0]
}


const formRef = ref()

/**
 * 查询
 */
const query = () => {
  // 根据formData过滤数据
  let data = tableData;
  if (formData.name) {
    data = tableData.filter(item => {
      return item.name.includes(formData.name);
    });
  }
  if (formData.sex) {
    data = data.filter(item => {
      return item.sex === formData.sex;
    })
  }
  tableDataSource.value = data;
}

/**
 * 重置
 */
const reset = () => {
  formRef.value.resetFields()
}

onMounted(() => {
  getSexList()
})

// 表单数据变化时,查询
watch(formData, () => {
  query()
})
</script>
<style scoped>

</style>

练习题

练习题参考答案:

<!--开发一个todo 列表应用-->
<template>
  <div class="container">
    <a-input placeholder="请输入待办事项" v-model:value="inputValue" @pressEnter="addTodo"/>
    <a-list>
      <a-list-item v-for="(item,index) in todoList" :key="item">
        <a-checkbox v-model:checked="item.checked" :disabled="item.disabled"
                    @change="selectTodo(index)">
          {
  
  { item.label }}
        </a-checkbox>
        <a-button size="small" @click="deleteTodo(index)">x</a-button>
      </a-list-item>
    </a-list>
  </div>
</template>

<script setup>
import {ref, reactive} from 'vue';

const inputValue = ref('');
const todoList = reactive([]);

// 添加事件
const addTodo = () => {
  if (inputValue.value.trim()) {
    todoList.push({
      label: inputValue.value,
      value: inputValue.value,
      disabled: false,
      checked: false
    });
    inputValue.value = '';
  }
};

// 复选框选中事件
const selectTodo = (index) => {
  todoList[index].checked = !!todoList[index].checked;
  todoList[index].disabled = todoList[index].checked;
};

// 删除事件
const deleteTodo = (index) => {
  todoList.splice(index, 1);
};
</script>

<style scoped>
.container {
  width: 50%;
  margin: 10px auto;
}
</style>

若碰到其他的问题 可以私信我 一起探讨学习
如果对你有所帮助还请
点赞 收藏 谢谢~!
关注收藏博客 持续更新中

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文件上传2

BUUCTF 你传你&#x1f40e;呢 先上传.htaccess 修改格式 即可上传成功 返回上传图片格式的木马 用蚁剑连接 5ecf1cca-59a1-408b-b616-090edf124db5.node5.buuoj.cn:81/upload/7d8511a847edeacb5385299396a96d91/rao.jpg 即可得到flag [GXYCTF2019]BabyUpload

网安加·百家讲坛 | 樊山:数据安全之威胁建模

作者简介&#xff1a;樊山&#xff0c;锦联世纪教育能源工业互联网数字安全CSM(新能源运维师)课程特聘培训讲师&#xff0c;哈尔滨工业大学&#xff08;深圳&#xff09;信飞合创数据合规联合实验室特聘专家&#xff0c;武汉赛博网络安全人才研究中心资深专家&#xff1b;近24年…

联想Y7000+RTX4060+i7+Ubuntu22.04运行DeepSeek开源多模态大模型Janus-Pro-1B+本地部署

直接上手搓了&#xff1a; conda create -n myenv python3.10 -ygit clone https://github.com/deepseek-ai/Janus.gitcd Januspip install -e .pip install webencodings beautifulsoup4 tinycss2pip install -e .[gradio]pip install pexpect>4.3python demo/app_januspr…

冬天适合养什么鱼?

各位鱼友们&#xff0c;冬天来了&#xff0c;是不是还在为养什么鱼而烦恼&#xff1f;别担心&#xff0c;今天就来给大家好好推荐一些适合冬天养的鱼&#xff0c;让你的水族箱在寒冷的冬天也能生机勃勃&#xff01; 一、金鱼&#xff1a;冬日里的“小暖男” 金鱼绝对是冬季养鱼…

2024年终总结

回顾 今年过年没回老家&#xff0c;趁着有时间&#xff0c;总结一下24年吧。 我把23年看做是打基础的一年&#xff0c;而24年主要是忙于项目的一年&#xff0c;基本上大部分时间都是忙着交付软件&#xff0c;写的一些文章也大部分都是项目中遇到的问题和解决方案&#xff0c;虽…

安宝特方案 | 智能培训:安宝特AR如何提升企业技能培训的效率与互动性

随着企业不断推进数字化转型&#xff0c;传统培训方式已无法满足现代企业对高效、灵活培训的需求。尤其在技术更新频繁、工艺流程复杂、员工流动性大的环境中&#xff0c;传统培训模式的局限性愈加明显。为了提升培训质量、降低培训成本&#xff0c;并帮助员工迅速掌握新技能&a…

1.27补题 回训练营

E 智乃的小球 题目描述 在一条无限长的水平直线上&#xff0c;有 n 个小球&#xff0c;每个小球的质量相同&#xff0c;体积可以忽略不计。这些小球初始时位于直线上的不同位置&#xff0c;并且每个小球有一个初始速度&#xff0c;速度为 -1 m/s 或 1 m/s。速度为 -1 m/s 表示…

Spring Boot 实现文件上传和下载

文章目录 Spring Boot 实现文件上传和下载一、引言二、文件上传1、配置Spring Boot项目2、创建文件上传控制器3、配置文件上传大小限制 三、文件下载1、创建文件下载控制器 四、使用示例1、文件上传2、文件下载 五、总结 Spring Boot 实现文件上传和下载 一、引言 在现代Web应…

CTFSHOW-WEB入门-命令执行39-53

题目&#xff1a;web 39 题目&#xff1a;解题思路&#xff1a;分析代码可以知道题目要求get一个c的参数&#xff0c;并且过滤了flag&#xff0c;大小写均过滤&#xff0c;于是可以想到使用&#xff1f;或者*通配符绕过。这里有include函数&#xff0c;由于include是个漏洞函数…

OpenCSG月度更新2025.1

1月的OpenCSG取得了一些亮眼的成绩 在2025年1月&#xff0c;OpenCSG在产品和社区方面继续取得了显著进展。产品方面&#xff0c;推出了AutoHub浏览器自动化助手&#xff0c;帮助用户提升浏览体验&#xff1b;CSGHub企业版功能全面升级&#xff0c;现已开放试用申请&#xff0c…

HTML(快速入门)

欢迎大家来到我的博客~欢迎大家对我的博客提出指导&#xff0c;有错误的地方会改进的哦~点击这里了解更多内容 目录 一、前言二、HTML基础2.1 什么是HTML?2.2 认识HTML标签2.2.1 HTML标签当中的基本结构2.2.2 标签层次结构 2.3 HTML常见标签2.3.1 标题标签2.3.2 段落标签2.3.3…

二叉树-堆(补充)

二叉树-堆 1.二叉树的基本特性2.堆2.1.堆的基本概念2.2.堆的实现2.2.1.基本结构2.2.2.堆的初始化2.2.3.堆的销毁2.2.4.堆的插入2.2.5.取出堆顶的数据2.2.6.堆的删除2.2.7.堆的判空2.2.8.堆的数据个数2.2.9.交换2.2.10.打印堆数据2.2.11.堆的创建2.2.12.堆排序2.2.13.完整代码 3…

JVM01_概述、跨平台原理、分类、三大商业虚拟机

①. 什么是JVM&#xff1f; ①. JVM 是 java虚拟机&#xff0c;是用来执行java字节码(二进制的形式)的虚拟计算机 ②. jvm是运行在操作系统之上的&#xff0c;与硬件没有任何关系 ②. Java的跨平台及原理 ①. 跨平台&#xff1a;由Java编写的程序可以在不同的操作系统上运行&am…

实现基础的shell程序

1. 实现一个基础的 shell 程序&#xff0c;主要完成两个命令的功能 cp 和 ls 1.1.1. cp 命令主要实现&#xff1a; ⽂件复制⽬录复制 1.1.2. ls 命令主要实现&#xff1a; ls -l 命令的功能 1.1. 在框架设计上&#xff0c;采⽤模块化设计思想&#xff0c;并具备⼀定的可扩…

idea修改模块名导致程序编译出错

本文简单描述分别用Idea菜单、pom.xml文件管理项目模块module 踩过的坑&#xff1a; 通过idea菜单创建模块&#xff0c;并用idea菜单修改模块名&#xff0c;结构程序编译报错&#xff0c;出错的代码莫名奇妙。双击maven弹窗clean时&#xff0c;还是报错。因为模块是新建的&am…

C27.【C++ Cont】时间、空间限制和STL库的简单了解

&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;春节篇&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8;&#x1f9e8; 目录 1.竞赛中的…

ResNet 残差网络

目录 网络结构 残差块&#xff08;Residual Block&#xff09; ResNet网络结构示意图 残差块&#xff08;Residual Block&#xff09;细节 基本残差块&#xff08;ResNet-18/34&#xff09; Bottleneck残差块&#xff08;ResNet-50/101/152&#xff09; 残差连接类型对比 变体网…

组件框架漏洞

一.基础概念 1.组件 定义&#xff1a;组件是软件开发中具有特定功能或特性的可重用部件或模块&#xff0c;能独立使用或集成到更大系统。 类型 前端 UI 组件&#xff1a;像按钮、下拉菜单、导航栏等&#xff0c;负责构建用户界面&#xff0c;提升用户交互体验。例如在电商 AP…

电脑无法开机,重装系统后没有驱动且驱动安装失败

电脑无法开机&#xff0c;重装系统后没有驱动且驱动安装失败 前几天电脑突然坏了&#xff0c;电脑卡住后&#xff0c;强制关机&#xff0c;再开机后开机马上就关机。尝试无数次开机后失败&#xff0c;进入BIOS界面&#xff0c;发现已经没有Windows系统了。重新安装系统后&…

NLP自然语言处理通识

目录 ELMO 一、ELMo的核心设计理念 1. 静态词向量的局限性 2. 动态上下文嵌入的核心思想 3. 层次化特征提取 二、ELMo的模型结构与技术逻辑 1. 双向语言模型&#xff08;BiLM&#xff09; 2. 多层LSTM的层次化表示 三、ELMo的运行过程 1. 预训练阶段 2. 下游任务微调 四、ELMo的…