侧边栏壁纸
博主头像
牧云

怀璧慎显,博识谨言。

  • 累计撰写 84 篇文章
  • 累计创建 9 个标签
  • 累计收到 8 条评论

目 录CONTENT

文章目录

Vue3入门

秋之牧云
2025-11-07 / 0 评论 / 0 点赞 / 85 阅读 / 0 字

1. 特性

声明式、响应式、组件化

2. 环境搭建

2.1. 安装Node.js

node -v
npm -v

3. 创建项目

3.1. 安装官方脚手架并创建项目

npm create vue@latest

3.2. 目录解释

  • node_modules : 项目依赖包文件夹,比如通过 npm install 包名 安装的包都会放在这个目录下;

  • public : 公共资源目录,用于存放公共资源,如 favicon.ico 图标等;

  • index.html : 首页;

  • package.json : 项目描述以及依赖;

  • package-lock.json : 版本管理使用的文件;

  • README.md : 用于项目描述的 markdown 文档;

  • src : 核心文件目录,源码都放在这里面;

进入 src 文件夹

  • assets : 静态资源目录,用于存放样式、图片、字体等;

  • components: 组件文件夹,通用的组件存放目录;

  • App.vue: 主组件,也是页面的入口文件,所有页面都是在 App.vue 下进行路由切换的;

  • main.js : 入口 Javascript 文件;

3.3. 启动项目

# 安装项目所需依赖
npm install
# 启动项目
npm run dev

3.4. 打包项目

npm run build

执行成功后,会在项目文件夹中看到多了一个 dist 文件夹

该文件下放置的就是编译后的静态文件,如 htmlcssjs 等相关文件

4. 语法

4.1. {{ }}插值表达式

插值表达式支持四则运算、比较运算符、数值操作、三目运算符、数组操作、对象操作等

<template>
  <!-- 字符串 -->
  <div>{{ obj.title }}</div>
  <div>{{ obj.num + "犬小哈教程" }}</div>
  <div>{{ obj.title.length }}</div>

  <!-- 数值 -->
  <div>{{ obj.num }}</div>
  <div>{{ obj.num + obj.num2 }}</div>
  <div>{{ obj.num > obj.num2 }}</div>
  <div>{{ obj.num.toFixed(2) }}</div>

  <!-- 布尔类型 -->
  <div>{{ obj.isSuccess }}</div>

  <!-- 数组 -->
  <div>{{ obj.arr }}</div>

  <!-- 对象 -->
  <div>{{ obj.subObj }}</div>
  <div>{{ obj.subObj.domain }}</div>

  <!-- 三目运算符 -->
  <div>{{ obj.isSuccess ? 'true' : 'false' }}</div>
</template>

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

  // reactive 函数用于响应式对象
  const obj = reactive({
    title: 'Hello',
    num: 1,
    num2: 2,
    isSuccess: true,
    arr: [1, 2, 3, 4],
    subObj: {
      title: '犬小哈',
      domain: 'www.quanxiaoha.com'
    }
  })
</script>

4.2. reactiveref创建响应式数据的两种方式

reactiveref 的主要区别对比

对比维度

ref

reactive

适用数据类型

基本类型(如 numberstringboolean)和对象类型均可

仅适用于对象类型(如普通对象、数组、MapSet 等)

访问方式

需通过 .value 访问或修改值(在 <template> 中自动解包,无需 .value

直接访问或修改属性,无需 .value

内部实现原理

基本类型使用 Object.defineProperty 劫持 .value;对象类型内部调用 reactive

基于 ES6 Proxy + Reflect 实现深层响应式

是否可整体替换

✅ 可以:x.value = newValue

❌ 不可以:重新赋值会丢失响应性

解构是否保持响应性

toRefstoRef 可保持响应性

❌ 直接解构会丢失响应性,需配合 toRefs 使用

典型使用场景

简单值、需要频繁替换整个值、逻辑复用函数返回值

复杂对象结构、状态集中管理(如表单、配置对象)

注:ref 在用于对象时,其内部会自动调用 reactive 转为代理对象 。
官方推荐优先使用 ref,因其更灵活且避免 reactive 的常见陷阱 。

4.3. v-text指令:文本插值

<template>
  <div>
    <!-- v-text文本插值  -->
    <div v-text="obj.title"></div>
  </div>
</template>

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

// reactive 函数用于响应式对象
const obj = ref({
  title: 'Hello',
  num: 1,
  num2: 2,
  isSuccess: true,
  arr: [1, 2, 3, 4],
  subObj: {
    title: '犬小哈',
    domain: 'www.quanxiaoha.com'
  }
})
</script>


<style scoped>

</style>

4.4. v-once指令:只会执行一次

<template>
  <div>
    <!--  v-once只会执行一次  -->
    <div v-once>{{ input }}</div>
    <div>{{ input }}</div>
    <input v-model="input">
  </div>
</template>

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

const input = ref('测试v-once');

</script>


<style scoped>

</style>

4.5. v-html指令:文本插值,解析html代码

<template>
  <div>
    <!--  v-html解析html代码  -->
    <div v-html="htmlText"></div>
    <div v-text="htmlText"></div>
  </div>
</template>

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

const htmlText = ref('<div>HTML</div>');

</script>


<style scoped>

</style>

4.6. v-bind指令:属性绑定

v-bind 指令可用于绑定 HTML 属性,它们包括 classsrctitle 等等

<template>
  <div>
    <!--  v-bind属性绑定  -->
    <a v-bind:href="linksUrl">link</a>
    <!--  v-bind简写形式  -->
    <a :href="linksUrl">link</a>
  </div>
</template>

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

const linksUrl = ref('https://www.baidu.com');

</script>


<style scoped>

</style>

4.6.1. 绑定css样式

<template>
  <div>
    <!--  绑定css样式  -->
    <div class = "black" :class="{ red: isActive }">绑定css样式</div>
    <input v-model="isActive"></input>
  </div>
</template>

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

const isActive = ref(true);

</script>


<style scoped>
  .black {
    color: black;
  }
  .red {
    color: red;
  }
</style>

{ red: isActive } 是Vue的对象语法,用于根据 isActive 的布尔值来决定是否给元素添加 red 这个CSS类名。后添加的class会覆盖前面同等级的class。

4.6.2. 通过数组绑定多个样式

<template>
  <div>
    <!-- 通过数组绑定多个样式   -->
    <p :class="[classes.color, classes.fontSize, classes.background]">通过数组绑定多个样式</p>
  </div>
</template>

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

const classes = ref({
  color: 'red',
  fontSize: '20px',
  background: 'yellow'
})

</script>


<style scoped>
.black {
  color: black;
}

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

4.6.3. 通过三目运算绑定css样式

<template>
  <div>
    <!--   通过三目运算绑定样式 -->
    <p :class="isActive ? 'red' : ''">通过三目运算绑定样式</p>
  </div>
</template>

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

const isActive = ref(true);

</script>


<style scoped>
.black {
  color: black;
}

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

4.7. v-if指令:条件渲染

<template>
  <div>
    <!--  vi-if条件渲染  -->
    <div v-if="isShow">vi-if条件渲染</div>
  </div>
</template>

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

const isShow = ref(true);
</script>


<style scoped>

</style>

4.7.1. v-else指令

<template>
  <div>
    <!--  vi-if条件渲染  -->
    <div v-if="isShow">vi-if条件渲染</div>
    <div v-else>v-else渲染</div>
  </div>
</template>

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

const isShow = ref(false);

</script>


<style scoped>

</style>

4.7.2. v-else-if指令

<template>
  <div>
    <!--  vi-if条件渲染  -->
    <div v-if="isShow === 1">vi-if条件渲染</div>
    <div v-else-if="isShow === 2">v-else-if渲染</div>
    <div v-else>v-else渲染</div>
  </div>
</template>

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

const isShow = ref(3);

</script>


<style scoped>

</style>

4.8. v-show指令:显示与隐藏

<template>
  <div>
    <!--  v-show指令  -->
    <div v-show="isShow === 1">v-show指令</div>
  </div>
</template>

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

const isShow = ref(3);

</script>


<style scoped>

</style>

<div data-v-7a7a37b1="" style="display: none;">v-show指令</div>

4.9. v-for指令:循环

<template>
  <div>
    <!--  v-for  -->
    <table border="1">
      <thead>
        <tr>
          <th>序号</th>
          <th>名称</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item, index) in list" :key="index">
          <td>{{ index + 1 }}</td>
          <td>{{ item }}</td>
        </tr>
      </tbody>
    </table>
</template>

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

  const list = ref(["JS", "Vue", "Java", "Python"]);

</script>


<style scoped>

</style>

:key="index" 可为每项提供一个唯一 key 属性,目的是为了方便的跟踪每个节点,这对重用和重新排列现有元素非常有帮助。

4.9.1. 遍历对象数组

<template>
  <h1>犬小哈教程列表</h1>
  <table border="1" width="600px">
    <tr>
      <td>ID</td>
      <td>名称</td>
      <td>阅读量</td>
    </tr>
    <tr v-for="(tutorial, index) in tutorials" :key="index">
      <td>{{ tutorial.id }}</td>
      <td>{{ tutorial.name }}</td>
      <td>{{ tutorial.viewNum }}</td>
    </tr>
  </table>
</template>

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

  // 定义一个教程列表数组, 元素为对象,包含 ID、教程名称、被阅读数 3 个字段
  const tutorials = reactive([
    {id: 1, name: "Vue 3 教程", viewNum: "12092"},
    {id: 2, name: "IDEA 教程", viewNum: "90236"},
    {id: 3, name: "Docker 教程", viewNum: "5902"},
  ])
</script>

4.9.2. 遍历

<template>
  <p v-for="(value, key, index) in tutorial" :key="index">
    字段名:{{ key }},字段值:{{ value }}
  </p>
</template>

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

  // 定义一个对象,包含 ID、教程名称、被阅读数 3 个字段
  const tutorial = reactive({id: 1, name: "Vue 3 教程", viewNum: "12092"},)
</script>

4.10. v-on指令:绑定事件监听

<template>
  <div>
    <!--  v-on事件监听  -->
    <button v-on:click="onClick">点击</button>
    <!--  v-on简写形式  -->
    <button @click="onClick">点击</button>
  </div>
</template>

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

const onClick = () => {
  alert("onClick")
}

</script>


<style scoped>

</style>

4.10.1. 参数传递

<template>
  <div>
    <!--  v-on事件监听  -->
    <button v-on:click="onClick('Hello')">点击</button>
    <button @click="onClick('World')">点击</button>
  </div>
</template>

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

const onClick = (value) => {
  alert("onClick:" +  value)
}

</script>


<style scoped>

</style>

4.10.2. 事件详情

<template>
  <div>
    <!--  v-on事件监听  -->
    <button v-on:click="onClick($event, 'Hello')">点击</button>
    <button @click="onClick($event, 'World')">点击</button>

    <button @click="showMousePosition">显示鼠标坐标</button>
  </div>
</template>

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

const showMousePosition = (event) => {
  alert(`鼠标坐标为:${event.clientX}, ${event.clientY}`)
}

const onClick = (event, value) => {
  alert(`onClick:${event.clientX}` + value)
}

</script>


<style scoped>

</style>

注意使用反撇号`

4.10.3. 事件修饰符

  • .stop:阻止事件冒泡。

  • .prevent:阻止事件的默认行为。

  • .capture:事件捕获模式,事件从外部元素向内部元素传播时触发。

  • .self:只在当前元素自身触发事件时才调用事件处理函数。

  • .once:事件只会触发一次。

  <!-- 阻止单击事件冒泡 -->
  <a @click.stop="clickMe"></a>
  <!-- 提交事件不再重载页面 -->
  <form v-on:submit.prevent="onSubmit"></form>
  <!-- 添加事件侦听器时使用事件捕获模式 -->
  <div @click.capture="clickTwo"></div>
  <!-- 只有当事件在该元素本身(非子元素)触发时触发回调 -->
  <div @click.self="clickThree"></div>
  <!-- 只有修饰符 -->
  <form v-on:submit.prevent></form>
  <!-- 修饰符串联模式 -->
  <a @click.stop.prevent="clickFour"></a>
<template>
  <a href="https://www.quanxiaoha.com">犬小哈教程</a><br>
  <a href="https://www.quanxiaoha.com" @click.prevent="goXiaohaWebsit1">犬小哈教程</a><br>
  <a href="https://www.quanxiaoha.com" @click="goXiaohaWebsit2($event)">犬小哈教程</a>
</template>

<script setup>
  const goXiaohaWebsit1 = () => {
  }

  const goXiaohaWebsit2 = (e) => {
    // 阻止
    e.preventDefault();
  }
</script>

上述代码中,只有第一个链接可以正常跳转,后面两个链接都被阻止了。

4.11. 按键修饰符

可以使用按键修饰符来监听键盘事件,并执行相应的事件处理函数。按键修饰符可以帮助你更精确地控制用户与你的应用程序的交互。

以下是一些常用的按键修饰符和它们对应的功能:

按键修饰符

功能

.enter

回车键

.tab

Tab 键

.delete

删除键或退格键

.esc

Escape 键

.space

空格键

.up

上箭头键

.down

下箭头键

.left

左箭头键

.right

右箭头键

.ctrl

Control 键

.alt

Alt 键

.shift

Shift 键

.meta

Meta/Command/Windows 键(通常是 Command 键在 macOS 上,Windows 键在 Windows 上)

.exact

精确匹配修饰符,确保修饰符和按键完全匹配

这些修饰符可以与 @keyup@keydown 等事件监听器一起使用,以监听特定键盘事件,并执行相应的操作。

<template>
  <input @keyup.enter="handleEnterKey"/>
  <p>{{ message }}</p>
</template>

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

  const message = ref('')

  // 回车键对应事件
  const handleEnterKey = () => {
    message.value = '您按了回车键了'
  }

</script>

4.12. v-model指令:双向绑定

4.12.1. 文本框双向绑定

<template>
  <div>
    <input v-model="message" placeholder="请输入内容" />
    <p>你输入的内容是:{{ message }}</p>
  </div>
</template>

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

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

4.12.2. 复选框双向绑定

<template>
  <div>
    兴趣爱好:
    <input type="checkbox" v-model="interests" value="唱"/><label>唱🎤</label>
    <input type="checkbox" v-model="interests" value="跳"/><label>跳</label>
    <input type="checkbox" v-model="interests" value="Rapper"/><label>Rapper</label>
    <input type="checkbox" v-model="interests" value="篮球"/><label>篮球🏀</label>
    <p>您的爱好是:{{ interests }}</p>
  </div>
</template>

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

const interests = ref([])
</script>

4.12.3. 单选框双向绑定

<template>
  <div>
    性别:
    <input type="radio" v-model="sex" value="女"/><label>女</label>
    <input type="radio" v-model="sex" value="男"/><label>男</label>
    <p>您的性别是:{{ sex }}</p>
  </div>
</template>

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

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

4.12.4. 下拉框双向绑定

<template>
  <div>
    <select v-model="selected">
      <option disabled value="">---请选择---</option>
      <option value="1">《犬小哈教程》</option>
      <option value="2">《Docker 教程》</option>
      <option value="3">《Vue 3 教程》</option>
    </select>

    <p>您选择的是:{{ selected }}</p>
  </div>
</template>

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

const selected = ref(1)
</script>

4.13. 计算属性

使用场景:

  • 数据过滤和排序:根据特定条件过滤或排序数据。

  • 动态类名和样式:根据状态动态添加 CSS 类或样式。

  • 动态表单验证:根据用户输入实时验证表单数据。

  • 复杂逻辑的处理:处理需要依赖多个属性或状态的复杂业务逻辑。

  • 动态计算属性:根据条件动态生成计算属性。

  • 数据映射和转换:将原始数据转换成展示需要的格式。

  • 嵌套数据的处理:处理嵌套结构的数据,提取或计算所需的属性。

  • 权限控制:根据用户权限显示或隐藏特定的界面元素。

  • 状态管理:将状态进行计算,返回派生状态。

  • 实时搜索和过滤:根据搜索词实时过滤显示的数据。

  • 复杂动画逻辑:计算动画的开始、结束状态等属性。

  • 实时统计和分析:实时计算数据的总数、平均值、最大值等。

在这个例子中,discountedPrice 是一个计算属性,它依赖于 goods 商品对象中的 pricediscount 两个属性的值。当 pricediscount 发生变化时,discountedPrice 会自动重新计算,并渲染到页面中。

<template>
  <div>
    <p>商品原价:{{ goods.price }}</p>
    <p>折扣:<input v-model="goods.discount"></p>
    <p>最终价格:{{ discountedPrice }}</p>
  </div>
</template>

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

const goods = reactive({
  // 原价
  price: 100,
  // 折扣价
  discount: 0.1
})

// 最终价格
const discountedPrice = computed(() => goods.price * (1 - goods.discount))
</script>

在这个例子中,computedBooks 是一个计算属性,它依赖于 searchText 查询关键词这个变量。当 searchText发生变化时,computedBooks 会自动重新计算,从 books 数组中实时筛选出包含对应关键词的数据。

<template>
  <div>
    <input v-model="searchText" placeholder="请输入查询关键词" />
    <ul>
      <li v-for="(item, index) in computedBooks" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

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

let books = [
  '犬小哈教程',
  'Java 教程',
  'Vue3 项目实战',
  'Spring Boot 项目实战',
]

// 查询关键词
const searchText = ref('')
// 筛选后的书籍
const computedBooks = computed(() => {
  const newBooks = books.filter(book => book.includes(searchText.value))
  return newBooks
})
</script>

计算属性和方法的区别

  • 计算属性适用于依赖多个响应式属性或需要复杂逻辑处理的情况,它具有自动依赖追踪和缓存机制,只有依赖的响应式属性发生变化时才会重新计算。

  • 方法适用于简单的逻辑处理,它不具备缓存机制,每次在模板中使用方法时都会重新执行方法中的逻辑。

选择使用计算属性还是方法取决于你的需求。如果你的逻辑是简单的,而且不需要缓存,可以使用方法。如果你的逻辑较为复杂,或者需要依赖多个响应式属性,建议使用计算属性,因为它可以提高性能并使代码更加清晰。

4.14. 侦听属性

侦听属性允许你在数据变化时执行一些自定义操作,侦听属性允许你监视一个数据,并在数据变化时执行自定义的操作。这个操作可以是同步的,也可以是异步的,比如异步请求、数据持久化、动画等等。

使用场景

  • 异步操作:侦听属性允许执行异步操作,处理需要与服务器端或其他异步任务交互的逻辑。

  • 自定义逻辑:侦听属性使得你可以在数据变化时触发指定函数,例如触发动画、保存数据等。

  • 动态响应:侦听属性能够动态地响应数据的变化,无需手动监听 DOM 事件或定时器。

使用示例

在这个例子中,我们通过watch选项定义了一个侦听属性,它会监视inputText属性的变化,并在每次变化时打印日志,包括当前值和变更前的老值。

<template>
  <div>
    <input v-model="inputText">
  </div>
</template>

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

// 输入框内容
const inputText = ref('')

watch(inputText, (newText, oldText) => {
  console.log(`新值: ${newText}, 老值: ${oldText}`)
})

</script>

通过侦听属性来实现一个根据用户输入的查询关键词,来筛选对应书本的功能

在这个例子中,通过侦听属性对 searchText 属性监听,每当输入关键词变化时,都会对 books 数组进行筛选,并将包含关键词的书籍赋值给 searchBooks , 最终实现了实时搜索的效果。

<template>
  <div>
    <input v-model="searchText" placeholder="请输入查询关键词" />
    <ul>
      <li v-for="(item, index) in searchBooks" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

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

const books = [
  '犬小哈教程',
  'Java 教程',
  'Vue3 项目实战',
  'Spring Boot 项目实战',
]

// 查询关键词
const searchText = ref('')
// 筛选后的书籍
const searchBooks = ref([])

// 侦听属性
watch(searchText, (s) => {
  searchBooks.value = books.filter(book => book.includes(s))
})
</script>

5. 路由

Vue 官方提供的路由管理器 —— Vue Router。功能包括:

  • 嵌套路由映射

  • 动态路由选择

  • 模块化、基于组件的路由配置

  • 路由参数、查询、通配符

  • 展示由 Vue.js 的过渡系统提供的过渡效果

  • 细致的导航控制

  • 自动激活 CSS 类的链接

  • HTML5 history 模式或 hash 模式

  • 可定制的滚动行为

  • URL 的正确编码

5.1. 安装Vue Router

npm install vue-router

5.2. 路由模式

Vue Router 提供了两种主要的路由模式,分别是:

  • Hash 模式 :#号

  • History 模式:不带#号

5.3. Demo

  • 创配置路由:建路由js文件(@/router/index.js文件)

// 从 vue-router 中引入 createRouter, createWebHashHistory 方法
import { createRouter, createWebHashHistory } from 'vue-router'
// 引入组件
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'

// 定义一个路由数组,统一管理路由
const routes = [
  {
    path: '/', // 路由地址:首页
    name: 'home', // 命名路由
    component: Home // 对应的组件
  },
  {
    path: '/login', // 登录页
    name: 'login',
    component: Login // 对应的组件
  }
  // ...
]

// 使用 createRouter 方法创建路由实例
const router = createRouter({
  history: createWebHashHistory(), // 指定 history 模式,这里采用的是 hash 模式
  routes // 定义路由数组,相当于 routes: routes 的简写模式
})

// ES6 模块导出语句,它用于将 router 对象导出,以便其他文件可以导入和使用这个对象
export default router
  • 添加路由填充位:App.vue

<template>
  <router-view></router-view>
</template>

<script setup>

</script>

<style scoped>

</style>
  • 应用路由:main.js

import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
// 从 router 文件夹下引入路由实例
import router from './router'

createApp(App)
    .use(router)
    .mount('#app')

0

评论区