【Vue】Vue 快速教程

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。

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

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

相关文章

学习threejs,光晕效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言二、&#x1f340;光晕效果实现1. ☘…

powerbi之常用DAX函数使用介绍——提供数据源练习

前述&#xff1a; 本次使用数据是包含产品表、客户表、区域表、销售订单表的一份销售订单数据&#xff0c;数据源链接如下&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1micl_09hFrgz2aUBERkeZg 提取码&#xff1a;y17e 一、CALCULATE 1.语法结构 语法结构CALCUL…

使用Docker搭建WAF-开源Web防火墙VeryNginx

1、说明 VeryNginx 基于 lua_nginx_module(openrestry) 开发,实现了防火墙、访问统计和其他的一些功能。 集成在 Nginx 中运行,扩展了 Nginx 本身的功能,并提供了友好的 Web 交互界面。 文章目录 1、说明1.1、基本概述1.2、主要功能1.3、应用场景2、拉取镜像3、配置文件4、…

多线程——线程安全

目录 前言 一、观察线程不安全 二、线程安全概念 三、产生线程安全问题的原因 1.分析示例代码 2.线程随机调度 3.修改共享数据 4.原子性 5.可见性 6.指令重排序 四、解决示例代码的问题 结尾 前言 我们学习多线程编程的目的是为了能够实现“并发编程”&#xff0c;…

LSTM的变体

一、GRU 1、什么是GRU 门控循环单元&#xff08;GRU&#xff09;是一种循环神经网络&#xff08;RNN&#xff09;的变体&#xff0c;它通过引入门控机制来控制信息的流动&#xff0c;从而有效地解决了传统RNN中的梯度消失问题。GRU由Cho等人在2014年提出&#xff0c;它简化了…

C语言 | Leetcode C语言题解之第466题统计重复个数

题目&#xff1a; 题解&#xff1a; #include <stdlib.h> #include <stdio.h> #include <stdbool.h> #include <string.h> #include <math.h> #include <limits.h>#define MMAX(a, b) ((a) > (b)? (a) : (b)) #define MMIN(a,…

【项目】五子棋对战测试报告

目录 一、项目背景 二、项目功能 三、测试计划 1、功能测试&#xff1a; &#xff08;1&#xff09;测试用例&#xff1a; &#xff08;2&#xff09;实际执行测试的部分操作/截图 2、自动化测试 3、性能测试 一、项目背景 1、五子棋对战游戏 采用了前后端分离的方法来…

GO网络编程(七):海量用户通信系统5:分层架构

P323开始&#xff08;尚硅谷GO教程&#xff09;老韩又改目录结构了&#xff0c;没办法&#xff0c;和之前一样&#xff0c;先说下目录结构&#xff0c;再给代码&#xff0c;部分代码在之前讲过&#xff0c;还有知识的话由于本人近期很忙&#xff0c;所以这些就不多赘述了&#…

web自动化测试基础(从配置环境到自动化实现登录测试用例的执行,vscode如何导入自己的python包)

接下来的一段时间里我会和大家分享自动化测试相关的一些知识希望大家可以多多支持&#xff0c;一起进步。 一、环境的配置 前提安装好了python解释器并配好了环境&#xff0c;并安装好了VScode 下载的浏览器和浏览器驱动需要一样的版本号(只看大版本)。 1、安装浏览器 Chro…

vue-live2d看板娘集成方案设计使用教程

文章目录 前言v1.1.x版本&#xff1a;vue集成看板娘&#xff08;暂不使用&#xff0c;在v1.2.x已替换&#xff09;集成看板娘实现看板娘拖拽效果方案资源备份存储 当前最新调研&#xff1a;2024.10.2开源方案1&#xff1a;OhMyLive2D&#xff08;推荐&#xff09;开源方案2&…

SpringMVC2~~~

目录 数据格式化 基本数据类型可以和字符串自动转换 特殊数据类型和字符串间的转换 验证及国际化 自定义验证错误信息 细节 数据类型转换校验核心类DataBinder 工作机制 取消某个属性的绑定 中文乱码处理 处理json和HttpMessageConverter 处理Json-ResponseBody 处理…

go开发环境设置-安装与交叉编译(二)

1. 引言 Go语言&#xff0c;又称Golang&#xff0c;是Google开发的一门编程语言&#xff0c;以其高效、简洁和并发编程的优势受到广泛欢迎。作为一门静态类型、编译型语言&#xff0c;Go在构建网络服务器、微服务和命令行工具方面表现突出。 在开发过程中&#xff0c;开发者常…

吸毛效果好的宠物空气净化器分享,希喂、霍尼韦尔、米家实测

说起宠物空气净化器&#xff0c;几年前我可能会一脸鄙夷&#xff1a;为啥要花这种智商税冤枉钱&#xff1f; 直到之前养了一只猫&#xff0c;被家中乱飞的浮毛和滂臭的异味搞到头晕&#xff0c;于是作为i一个养宠的家电测评博主&#xff0c;索性对宠物空气净化器这玩意做了超级…

前端继承:原理、实现方式与应用场景

目录 一、定义 二、语法和实现方式 1.原型链继承 2.构造函数继承 3.组合继承 4.ES6类继承 三、使用方式 四、优点 五、缺点 六、适用场景 一、定义 前端继承是指在面向对象编程中&#xff0c;一个对象可以继承另一个对象的属性和方法。在前端领域&#xff0c;通常是指…

OpenCV高级图形用户界面(1)创建滑动条函数createTrackbar()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 创建一个滑动条并将其附加到指定的窗口。 该函数 createTrackbar 创建一个具有指定名称和范围的滑动条&#xff08;滑块或范围控制&#xff09;…

C语言之扫雷小游戏(完整代码版)

说起扫雷游戏&#xff0c;这应该是很多人童年的回忆吧&#xff0c;中小学电脑课最常玩的必有扫雷游戏&#xff0c;那么大家知道它是如何开发出来的吗&#xff0c;扫雷游戏背后的原理是什么呢&#xff1f;今天就让我们一探究竟&#xff01; 扫雷游戏介绍 如下图&#xff0c;简…

使用3080ti配置安装blip2

使用3080ti运行blip2的案例 本机环境&#xff08;大家主要看GPU&#xff0c;ubuntu版本和cuda版本即可&#xff09;&#xff1a;安装流程我最后安装的所有包的信息&#xff08;python 3.9 &#xff09;以供参考&#xff08;environment.yml&#xff09;&#xff1a; 本机环境&a…

【python实操】python小程序之计算对象个数、游戏更新分数

引言 python小程序之计算对象个数、游戏更新分数 文章目录 引言一、计算对象个数1.1 题目1.2 代码1.3 代码解释1.3.1 代码结构1.3.2 模块解释1.3.3 解释输出 二、游戏更新分数2.1 题目2.2 代码2.3 代码解释2.3.1 定义 Game 类2.3.2 创建 Game 实例并调用方法 三、思考3.1 计算对…

安卓13禁止锁屏 关闭锁屏 android13禁止锁屏 关闭锁屏

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 设置 =》安全 =》屏幕锁定 =》 无。 我们通过修改系统屏幕锁定配置,来达到设置屏幕不锁屏的配置。像网上好多文章都只写了在哪里改,改什么东西,但是实际上并未写明为什么要改那…

RabbitMQ 高级特性——死信队列

文章目录 前言死信队列什么是死信常见面试题死信队列的概念&#xff1a;死信的来源&#xff08;造成死信的原因有哪些&#xff09;死信队列的应用场景 前言 前面我们学习了为消息和队列设置 TTL 过期时间&#xff0c;这样可以保证消息的积压&#xff0c;那么对于这些过期了的消…