【Vue】Vue 快速教程

news2024/10/9 9:41:20

Vue tutorial

参考:教程 | Vue.js (vuejs.org)

该教程需要前置知识:HTML, CSS, JavaScript

学习前置知识,你可以去 MDN

Vue framework 是一个 JavaScript framework,以下简称 Vue,下面是它的特点

  • 声明式渲染(Declarative Rendering):即声明 JavaScript 对象,改变对象状态来更改 HTML,这个过程由 Vue 完成
  • 响应式(Reactivity):JavaScript 的对象状态改变会马上反映到 DOM(不知道 DOM 的去查 MDN 文档)

Declarative Rendering and Reactivity

Vue 实现了:

JavaScript Obejct <-> Vue <-> DOM

但是 Vue 显然是利用 JavaScript 机制,那就是 Proxy,Proxy 可以实现

JavaScript Object <-> Proxy <-> DOM

所以 Vue 把 Proxy 改造后封装成了 reactive(),调用这个 API 会返回一个特殊的对象,称之为响应式对象(reactive object)

  • reactive()
import { reactive } from 'vue'

const counter = reactive({
  count: 0
})

console.log(counter.count) // 0
counter.count++

但是 reactive() 参数只能是对象(还有数组和内置类型),Vue 又把 reactive() 改造封装成了 ref(),它也会返回一个响应式对象,并且带一个 .value property,只不过它的参数可以填写值。

  • ref()
import { ref } from 'vue'

const message = ref('Hello World!')

console.log(message.value) // "Hello World!"
message.value = 'Changed'

以上给 ref()reactive() 填写参数得到响应式对象的过程,就被成为数据绑定(data binding)。

Template syntax

在这里复习一下 HTML element 和 attribute 概念

Anatomy of an HTML element

这是 HTML element

在这里插入图片描述

这是 HTML attribute

在这里插入图片描述

在此之中,Class 为 attribute name,editor-note 为 attribute value

Vue 自己创造了一套 template language。最基本的数据绑定是文本插值(Text Interpolation),它可以改变 element 的 content,像这样

<span>{{ message }}</span>

这种语法被成为 “Mustache”语法 (即双大括号)。再结合上节讲到的 reactive object,我们可以这样写

import { ref } from 'vue'

const message = ref('Hello World!')

效果是这样的

在这里插入图片描述

可能你会有些疑问,为什么不是写 {{message.value}},因为它是 top-level property,会自动解包(unwrapping)

const object = { id: ref(1) }

比如这个里面,id 就不是 top-level property,如果你这么写

{{ object.id + 1 }}

渲染的结果将是 [object Object]1

在这里插入图片描述

你需要手动解包,才会渲染出 2

{{ object.id.value + 1 }}

在这里插入图片描述

Directive

v-xxx 就是一种 attribute,在它的 template language 中被称为 directive

v-bind

Attribute bind

在 Vue 中,Mustache 语法只能用于文本插值来改变 element content,没法儿操作 element attribute。而且 element attribute 是静态的,为了给 element attribute 绑定一个动态值,需要使用 Vue 的 v-bind directive

<div v-bind:id="dynamicId"></div>

冒号后面的 id 被称为 directive 的参数(argument),dynamicId 则为参数值,它会和响应式对象的 property 同步。它可以简写为

<div :id="dynamicId"></div>

例子:

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

const titleClass = ref('title')
</script>

<template>
  <h1 :class="titleClass">Make me red</h1>
</template>

<style>
.title {
  color: red;
}
</style>

v-on

Event Listen

可以通过 v-on 来监听 DOM event

<button v-on:click="increment">{{ count }}</button>

简写

<button @click="increment">{{ count }}</button>

点击 button 会触发 increment() 这个函数。

例子:

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

const count = ref(0)

function increment() {
  count.value++
}
</script>

<template>
  <button @click="increment">count is: {{ count }}</button>
</template>

v-model

Form bind

同时使用 v-bindv-on 对表单(form)进行绑定和监听

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

const text = ref('')

function onInput(e) {
  text.value = e.target.value
}
</script>

<template>
  <input :value="text" @input="onInput" placeholder="Type here">
  <p>{{ text }}</p>
</template>

啊,这么写实在太麻烦,所以 vue 提供了 v-model。当然,最好看一下它支持哪些 element。

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

const text = ref('')
</script>

<template>
  <input v-model="text" placeholder="Type here">
  <p>{{ text }}</p>
</template>

v-if and v-else

Conditional Rendering

v-ifv-else 可以根据条件来决定 element 是否在 DOM 中。

例子:

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

const awesome = ref(true)

function toggle() {
  awesome.value = !awesome.value
}
</script>

<template>
  <button @click="toggle">toggle</button>
  <h1 v-if="awesome">Vue is awesome!</h1>
  <h1 v-else>Oh no 😢</h1>
</template>

改变 awesome 的值来显示 “Vue is awesome!” 和 “Oh no 😢”。

v-for

当你想写一个列表时,一个个写列表的 element 实在太累了,如果有 1000 个那不就完蛋了,所以 v-for 可以通过循环,直接渲染出列表(当然,你得给相应的数据)

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

// 给每个 todo 对象一个唯一的 id
let id = 0

const newTodo = ref('')
const todos = ref([
  { id: id++, text: 'Learn HTML' },
  { id: id++, text: 'Learn JavaScript' },
  { id: id++, text: 'Learn Vue' }
])

function addTodo() {
  todos.value.push({ id: id++, text: newTodo.value })
  newTodo.value = ''
}

function removeTodo(todo) {
  todos.value = todos.value.filter((t) => t !== todo)
}
</script>

<template>
  <form @submit.prevent="addTodo">
    <input v-model="newTodo" required placeholder="new todo">
    <button>Add Todo</button>
  </form>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      {{ todo.text }}
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
</template>

computed()

template 里面可以写这种计算表达式

<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

但是这种计算写在 template 里是真的不好理解,个人感觉在结构上 View 里不能有逻辑,所以尽量不要这么写。

所以我们可以用 computed(),这样

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

const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
</script>

<template>
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</template>

它和 method() 最大区别在于,它是只有在响应式对象更新时才会重新被调用和计算,否则就会直接返回缓存值,即 books 不变,重渲染(比如页面刷新,更新)时 computed() 不会被调用,而 method() 则会。插嘴一句 method(),重渲染时总会被调用。

Lifecycle and Template Refs

手动用 JavaScript 操作 DOM 是一件苦差事,所以我们用 vue 来帮忙,但是有时我们不得不操作 DOM,这个时候我们就得使用模板引用(template ref)

这个时候就要使用 ref attribute

<p ref="pElementRef">hello</p>

如果要访问这个 ref,我们需要声明(declare)ref 并初始化

const pElementRef = ref(null)

注意我们使用给 ref 的 argument 为 null,这是因为<script setup> 执行时,DOM 还没有初始化,template ref 只能在挂在(mount)后访问,所以我们可以使用生命周期钩子(lifecycle hook)比如 onMounted(),关于 lifecycle 请看生命周期图示

例子:

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

const pElementRef = ref(null)

onMounted(() => {
  pElementRef.value.textContent = 'mounted!'
})
</script>

<template>
  <p ref="pElementRef">hello</p>
</template>

watch()

watch() 可以监察一个 ref,并触发一个 callback function,比如下面的例子就是监察 todoId,触发 fetchData

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

const todoId = ref(1)
const todoData = ref(null)

async function fetchData() {
  todoData.value = null
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
  )
  todoData.value = await res.json()
}

fetchData()

watch(todoId, fetchData)
</script>

<template>
  <p>Todo id: {{ todoId }}</p>
  <button @click="todoId++" :disabled="!todoData">Fetch next todo</button>
  <p v-if="!todoData">Loading...</p>
  <pre v-else>{{ todoData }}</pre>
</template>

Component

Vue application 常常是多个 component 嵌套创建,所以就有 parent component 包含 child component

如果要使用 child component,就需要导入它

import ChildComp from './ChildComp.vue'

使用 child component

<ChildComp />

例子:

<!--App.vue-->

<script setup>
import ChildComp from './ChildComp.vue'
</script>

<template>
  <ChildComp />
</template>

Props

child component 可以通过 props 从 parent component 获取动态数据

<!--ChildComp.vue-->
<script setup>
const props = defineProps({
  msg: String
})
</script>

注意,defineProps() 是一个 runtime marcro,不需要导入。

这样,msg 就可以在 child component 的 <template> 中使用

<template>
  <h2>{{ msg || 'No props passed yet' }}</h2>
</template>

而 parent component 则可以用 v-bind 传递数据

<!--App.vue-->
<ChildComp :msg="greeting" />

例子:

<!--App.vue-->
<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'

const greeting = ref('Hello from parent')
</script>

<template>
  <ChildComp :msg="greeting" />
</template>
<!--ChildComp.vue-->
<script setup>
const props = defineProps({
  msg: String
})
</script>

<template>
  <h2>{{ msg || 'No props passed yet' }}</h2>
</template>

child component 中采用的 “runtime declaration”,还有一种是如果你用 typescript,需要采用 “type-based declaration”,具体看官方文档。

Emits

child component 可以向 parent component 传 event,emit() 中,第一个 argument 是 event name,其他的会传给 event listener。

parent component 可以通过 v-on 监听 child-emitted event,并且可以将额外的 argument 赋值给 local state

<!--App.vue-->
<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'

const childMsg = ref('No child msg yet')
</script>

<template>
  <ChildComp @response="(msg) => childMsg = msg" />
  <p>{{ childMsg }}</p>
</template>
<!--ChildComp.vue-->
<script setup>
const emit = defineEmits(['response'])

emit('response', 'hello from child')
</script>

<template>
  <h2>Child component</h2>
</template>

Solots

除了 props,parent component 可以将 template 片段传给 child component,而在 child component,则可以使用 <slot> 来显示片段的内容。

<!--App.vue-->
<script setup>
import { ref } from 'vue'
import ChildComp from './ChildComp.vue'

const msg = ref('from parent')
</script>

<template>
  <ChildComp>Message: {{ msg }}</ChildComp>
</template>
<template>
  <slot>Fallback content</slot>
</template>

以上 parent component 中,<ChildComp> 的内容会传给 child component 中的 <slot>,最后渲染在 parent component 上。

在这里插入图片描述

Essential

Create application

application instance and root component

Vue application 通常是通过 createApp 来创建一个 application instance

createApp 的参数则被称为 root component,而且其他 component 则作为 root 的 child component,所以 vue application 是由 root component 和 child component 组成的。

一般这种创建代码都在 <project-name>/src/main.js

<!--main.js-->
import { createApp } from 'vue'
// 导入一个单组件
import App from './App.vue'
// 将这个单组件作为根组件
const app = createApp(App)

一个 Todo application 的例子

App (root component)
├─ TodoList
│  └─ TodoItem
│     ├─ TodoDeleteButton
│     └─ TodoEditButton
└─ TodoFooter
   ├─ TodoClearButton
   └─ TodoStatistics

mount application

application instance 必须调用 mount() 才能渲染,而必须的 argument 则为 DOM 的 element 或者 CSS selector

在 vue project 中一般在 <project-name>/index.html

<div id="app"></div>

注意 mount() 应该始终在应用配置完成后调用,简单点儿说就是最后调用。

Applicaiton configuration

application instance 会提供一个 config object,这样就可以配置 vue app,比如 app-level option,capture error

app.config.errorHandler = (err) => {
  /* 处理错误 */
}

或者 component registration

比如 global registration

app.component('TodoDeleteButton', TodoDeleteButton)

其他细节清参考 vue 文档。

Component registration

如果要使用 component,则必须是 registered

Global registration

使用 .component() method:

import { createApp } from 'vue'

const app = createApp({})

app.component(
  // the registered name
  'MyComponent',
  // the implementation
  {
    /* ... */
  }
)

如果使用 SFC,则

import MyComponent from './App.vue'

app.component('MyComponent', MyComponent)

Local registration

使用 component option

import ComponentA from './ComponentA.js'

export default {
  components: {
    ComponentA
  },
  setup() {
    // ...
  }
}

使用 SFC

<script setup>
import ComponentA from './ComponentA.vue'
</script>

<template>
  <ComponentA />
</template>

Toolchain

当你创建一个 vue project 时,手动新建目录和文件是很麻烦的事情,所有我们有项目脚手架(Project Scaffolding)来自动创建 project 基本的目录和文件。

Vite

尤雨溪开发的 build tool,支持 SFC,通过 Vite 创建项目:

npm create vue@latest

Vue CLI

基于 webpack 的 build tool,但现在是维护状态,建议使用 Vite。

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

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

相关文章

音频进阶学习三——离散时间信号与系统

文章目录 前言一、离散时间信号1.基本信号2.离散时间信号的分类3.离散时间信号的简单运算4.单位脉冲在运算中的作用 二、离散时间系统1.什么是离散时间系统2.离散系统的分类 总结 前言 前面博主介绍了信号中的连续时间信号和离散时间信号&#xff0c;数字信号也是离散时间信号…

1.一、MyBatis入门

一、MyBatis入门 我们做为后端程序开发人员&#xff0c;通常会使用Java程序来完成对数据库的操作。Java程序操作数据库&#xff0c;现在主流的方式是&#xff1a;Mybatis。 一、什么是MyBatis? MyBatis官网的解释&#xff1a; MyBatis 是一款优秀的持久层框架&#xff0c;它…

基于Zabbix进行服务器运行情况监测

文章目录 引言I Zabbix主要构成下载并安装Zabbix被监控主机安装zabbix agent创建被监控主机报警设置II 常见问题cannot use database "zabbix": its "users" table is empty (is this the Zabbix proxy database?)重置 Zabbix Web 界面密码Zabbix agent i…

【c++】初步了解类和对象2

1、类的作用域 类定义了一个新的作用域&#xff0c;类的所有成员都在类的作用域中。在类体外定义成员时&#xff0c;需要使用 :: 作用域操作符指明成员属于哪个类域。 如图&#xff0c;此时在类内声明了函数firstUniqChar()&#xff0c;在类外进行了函数体的具体定义。 但是却…

【成神之路】Ambari实战-050-UI-如何通过配置修改ambari样式

在Ambari中&#xff0c;通过自定义UI控件&#xff08;Widget&#xff09;&#xff0c;你可以灵活调整配置项的展现形式&#xff0c;使其更符合实际需求。这篇文章将详细介绍各种控件的使用&#xff0c;并提供代码示例和实际应用场景&#xff0c;帮助你成为UI配置的行家&#xf…

国家发改委等部门划时间点:到2026年底基本建成国家数据标准体系

摘要 【国家发改委等部门划时间点&#xff1a;到2026年底基本建成国家数据标准体系】10月8日&#xff0c;国家发改委等部门联合印发《国家数据标准体系建设指南》。《建设指南》提出计划&#xff0c;到2026年底&#xff0c;基本建成国家数据标准体系&#xff0c;围绕数据流通利…

jmeter学习(7)beanshell

beanshell preprocessor 发送请求前执行 beanshell postprocessor 发送请求前执行 获取请求相关信息 String body sampler.getArguments().getArgument(0).getValue(); String url sampler.getPath(); 获取响应报文 String responseprev.getResponseDataAsString(); 获…

应急响应:LinuxWindows实战排查

目录 应急响应 介绍&#xff1a; 应急流程&#xff1a; 抑制阶段&#xff1a; 对于Linux&#xff0c;一些常见的排查命令&#xff1a; 对于Windows&#xff0c;常见的排查命令&#xff1a; Windows应急&#xff08;一&#xff09; Windows应急&#xff08;二&#xff0…

C++ string类(超详细一次性讲解)(上)

1. 为什么学习string类&#xff1f; 1.1 C语言中的字符串 C语言中&#xff0c;字符串是以 \0 结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&…

Python OpenCV精讲系列 - 三维重建深入理解(十七)

&#x1f496;&#x1f496;⚡️⚡️专栏&#xff1a;Python OpenCV精讲⚡️⚡️&#x1f496;&#x1f496; 本专栏聚焦于Python结合OpenCV库进行计算机视觉开发的专业教程。通过系统化的课程设计&#xff0c;从基础概念入手&#xff0c;逐步深入到图像处理、特征检测、物体识…

细菌实例分割系统源码&数据集分享

细菌实例分割系统源码&#xff06;数据集分享 [yolov8-seg-EfficientFormerV2&#xff06;yolov8-seg-SPPF-LSKA等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Glob…

系分-数据库总结

历年试题2024年05月试题 BCN范式&#xff0c;模式分解&#xff0c;触发器类型2023年05月试题 NoSQL基本特点&#xff0c;NoSQL对比&#xff0c;混合数据库2022年05月试题4 两段锁&#xff0c;事务并发&#xff0c;数据一致&#xff0c;本地事务发布20…

生命的最高境界(深度好文)?

予人玫瑰&#xff0c;手有余香。 生命的最高境界&#xff0c;就一个字&#xff1a;给。 初级的快乐&#xff0c;是放任&#xff1b;中级的快乐&#xff0c;是自律&#xff1b;高级的快乐&#xff0c;是给予。 予人玫瑰&#xff0c;手有余香。 学会“给”&#xff0c;是我们一…

PCL 表面曲率下采样

目录 一、概述二、代码三、结果 一、概述 通过表面曲率信息对点云进行采样&#xff0c;选择表面曲率约束下的代表性点。 二、代码 #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/features/normal_3d.h&g…

《Python 安装指南:开启编程之旅》

《Python 安装指南&#xff1a;开启编程之旅》 在当今数字化的时代&#xff0c;编程已经成为一项越来越重要的技能。而 Python 作为一种简洁、高效且功能强大的编程语言&#xff0c;受到了众多开发者的青睐。无论是数据科学、人工智能、Web 开发还是自动化脚本编写&#xff0c…

2024.10.8 作业+思维导图

优化登录框&#xff1a; 当用户点击取消按钮&#xff0c;弹出问题对话框&#xff0c;询问是否要确定退出登录&#xff0c;并提供两个按钮&#xff0c;yes|No&#xff0c;如果用户点击的Yes&#xff0c;则关闭对话框&#xff0c;如果用户点击的No&#xff0c;则继续登录 当用户点…

gaussdb hccdp认证思考题02 GaussDB数据库应用程序开发指引

02_GaussDB数据库应用程序开发指引 1. &#xff08;单选题&#xff09;在JDBC中用于与数据库建立连接并指向SQL语句的接口是以下哪一项&#xff1f; A. java.sql.ResultSet B. java.sql.Driver C. java.sql.Connection D. javax.sql.DataSource --C 2. &#xff08;单选题…

、Redis 安装

Redis 安装 Redis 下载链接 [rootiZhp3i77hpofuqqxvoc790Z ~]# mkdir redis [rootiZhp3i77hpofuqqxvoc790Z ~]# ll 总用量 4 drwxr-xr-x 2 root root 4096 10月 8 15:23 redis [rootiZhp3i77hpofuqqxvoc790Z ~]# cd redis/ # 将 redis 安装包上传至当前目录下 # 解压当前文件…

《Windows PE》5.1 导出表

导出表&#xff08;Export Table&#xff09;是一个在可执行文件或动态链接库&#xff08;DLL&#xff09;中的数据结构&#xff0c;用于描述该文件中导出的函数、变量和其他符号。导出表通常位于DLL动态链接库中。 本节必须掌握的知识点&#xff1a; 导入表数据结构 PE中的导…

云计算:MySQL

第一周第一天-MySQL的SQL语句解析 数据库的介绍 什么是数据库 数据库是存储和管理数据的系统或集合&#xff0c;通常用于支持软件系统的高效数据处理和查询。它能够以结构化的方式组织数据&#xff0c;使用户可以快速存储、更新、查询和删除数据。数据库不仅保存数据&#xff0…