vuewatch

Vue watch侦听用法

Created: 9/21/2025 15:39:53
Updated: 9/22/2025 18:06:59
Exported: 9/22/2025 18:36:46
Link: https://chatgpt.com/c/68cfabc8-ec6c-8322-933a-f583e6d96af5

Prompt:vue中的watch侦听

Vue 中,watch 侦听器用来 侦听某个响应式数据的变化,并在变化时执行对应的回调函数。它非常适合用于:

  • 监听数据变化后执行异步或开销较大的操作(例如:发请求、操作本地存储)。
  • 监听路由参数、输入框值等,进行联动逻辑处理。

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export default {
data() {
return {
message: 'hello',
count: 0
}
},
watch: {
// 普通监听
message(newVal, oldVal) {
console.log('message 变了:', oldVal, '=>', newVal)
},

// 也可以监听多个数据
count(newVal, oldVal) {
if (newVal > 10) {
console.log('count 超过 10 了')
}
}
}
}

深度侦听 (deep)

对于对象或数组等引用类型,默认只监听引用本身的变化,不会追踪内部属性。
可以通过 deep: true 开启深度监听:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default {
data() {
return {
user: {
name: 'Tom',
age: 18
}
}
},
watch: {
user: {
handler(newVal, oldVal) {
console.log('user 改了:', newVal)
},
deep: true
}
}
}

立即执行 (immediate)

有时需要在侦听器初始化时立刻执行一次,可以用 immediate: true

1
2
3
4
5
6
7
8
9
10
11
12
13
export default {
data() {
return { keyword: '' }
},
watch: {
keyword: {
handler(newVal) {
console.log('搜索:', newVal)
},
immediate: true
}
}
}

侦听计算属性或路径

watch 也可以监听 计算属性 或者某个对象的 具体路径

1
2
3
4
5
6
7
8
9
10
11
watch: {
// 监听计算属性
fullName(val) {
console.log('fullName 改了:', val)
},

// 监听对象中的某个属性
'user.age'(newVal) {
console.log('user.age 改了:', newVal)
}
}

computed 的区别

  • computed:用于 派生数据,结果会缓存,适合依赖计算。
  • watch:用于 观察数据变化并触发副作用,常用于异步/开销大的操作。

Prompt:在vue3中呢

Vue 3 中,watch 的用法比 Vue 2 更灵活,主要体现在组合式 API(Composition API)中。


1. 选项式 API(和 Vue 2 类似)

Vue 3 仍然支持 watch 选项,写法基本一致:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default {
data() {
return {
message: 'hello',
count: 0
}
},
watch: {
message(newVal, oldVal) {
console.log('message 改了:', oldVal, '=>', newVal)
},
count(newVal) {
if (newVal > 10) {
console.log('count 超过 10 了')
}
}
}
}

2. 组合式 API watch

setup() 里可以通过 Vue 提供的 watch 函数来侦听:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { ref, watch } from 'vue'

export default {
setup() {
const message = ref('hello')
const count = ref(0)

// 监听单个 ref
watch(message, (newVal, oldVal) => {
console.log('message 改了:', oldVal, '=>', newVal)
})

// 监听多个数据
watch([message, count], ([newMsg, newCount], [oldMsg, oldCount]) => {
console.log('多个值变化:', newMsg, newCount)
})

return { message, count }
}
}

3. 深度侦听(deep)

监听对象时,默认只监听引用,不会追踪内部。
需要用 deep: true

1
2
3
4
5
6
7
8
9
10
11
12
13
import { ref, watch } from 'vue'

export default {
setup() {
const user = ref({ name: 'Tom', age: 18 })

watch(user, (newVal, oldVal) => {
console.log('user 改了:', newVal)
}, { deep: true })

return { user }
}
}

⚠️ 在 Vue 3 中,reactive 定义的对象,本身会被整体追踪,一般只要监听 reactive,不需要 deep,除非你真的要追踪嵌套属性。


4. 立即执行(immediate)

和 Vue 2 一样,可以立刻触发一次回调:

1
2
3
watch(message, (newVal) => {
console.log('立即执行:', newVal)
}, { immediate: true })

5. 监听计算属性 / getter

watch 的第一个参数可以是一个 getter 函数,这样就能监听计算属性或者某个路径:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { ref, watch, computed } from 'vue'

export default {
setup() {
const firstName = ref('Tom')
const lastName = ref('Jerry')

const fullName = computed(() => firstName.value + ' ' + lastName.value)

// 直接监听计算属性
watch(fullName, (newVal) => {
console.log('fullName 改了:', newVal)
})

// 监听对象的某个属性
const user = ref({ name: 'Tom', age: 18 })
watch(() => user.value.age, (newVal) => {
console.log('user.age 改了:', newVal)
})

return { firstName, lastName, user }
}
}

6. watchEffect(自动收集依赖)

Vue 3 新增了 watchEffect,不需要手动指定依赖,回调函数里用到的响应式数据会自动被追踪:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { ref, watchEffect } from 'vue'

export default {
setup() {
const count = ref(0)

watchEffect(() => {
console.log('count 的值是:', count.value)
})

setInterval(() => {
count.value++
}, 1000)

return { count }
}
}

watchEffect 更像是一个自动执行的副作用函数,适合逻辑比较简单的场景。

Prompt:如何侦听对象中的某个属性

Vue 3 中,如果只想侦听对象中的某个属性,有几种常见写法。


1. 用 getter 函数 指定属性

这是最推荐的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { ref, watch } from 'vue'

export default {
setup() {
const user = ref({ name: 'Tom', age: 18 })

// 只侦听 age
watch(() => user.value.age, (newVal, oldVal) => {
console.log('user.age 改了:', oldVal, '=>', newVal)
})

return { user }
}
}

👉 好处:只会在 age 变化时触发,不会受 name 变化影响。


2. 如果对象是 reactive

reactive 不能直接解构,否则会失去响应性。但也可以通过 getter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { reactive, watch } from 'vue'

export default {
setup() {
const user = reactive({ name: 'Tom', age: 18 })

// 监听某个属性
watch(() => user.age, (newVal, oldVal) => {
console.log('user.age 改了:', newVal)
})

return { user }
}
}

3. 监听多个属性

可以传数组:

1
2
3
watch([() => user.name, () => user.age], ([newName, newAge], [oldName, oldAge]) => {
console.log('name 或 age 变了:', newName, newAge)
})

4. 深度侦听(不推荐用来监听单个属性)

如果你用 deep: true 监听整个对象:

1
2
3
watch(user, (newVal) => {
console.log('user 整个对象变了:', newVal)
}, { deep: true })

⚠️ 这样会在 任意属性变化时触发,开销大,不适合只关心某个属性的场景。


结论:在 Vue 3 里,监听对象某个属性的最佳方式是用 getter 函数

1
watch(() => user.value.age, callback)

要不要我帮你整理一张 Vue 3 中侦听对象属性的几种写法对比表,让你快速知道在不同场景下用哪种?

Prompt:Uncaught SyntaxError:

The requested module ‘/src/api/emp.js’ does not provide an export named ‘default’

这个报错信息说明:你在某个地方写了

1
import xxx from '/src/api/emp.js'

但是 **/src/api/emp.js 文件里并没有 export default**。

  • import xxx from '...' → 要求文件里有 export default
  • import { foo } from '...' → 对应文件里必须有 export function fooexport const foo

Prompt:elementplus复选框获取数据的id

Element Plus 里,复选框如果要获取被选中的数据的 id,通常有两种场景:


1. 单独的 el-checkbox

最简单的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<el-checkbox-group v-model="checkedIds">
<el-checkbox v-for="item in list" :key="item.id" :label="item.id">
{{ item.name }}
</el-checkbox>
</el-checkbox-group>

<div>选中的 ID:{{ checkedIds }}</div>
</template>

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

const list = ref([
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' }
])

// 存放选中的 id 数组
const checkedIds = ref([])
</script>

👉 这里 :label="item.id" 就决定了绑定到 checkedIds 的值就是数据的 id


2. 在 el-table 中使用 el-table-column type="selection"

如果你用表格来展示数据,可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<template>
<el-table
:data="list"
@selection-change="handleSelectionChange"
style="width: 100%"
>
<!-- 多选框列 -->
<el-table-column type="selection" width="55" />

<el-table-column prop="id" label="ID" width="120" />
<el-table-column prop="name" label="姓名" />
</el-table>

<div>选中的 ID:{{ selectedIds }}</div>
</template>

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

const list = ref([
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' }
])

// 存放选中的整行对象
const multipleSelection = ref([])

// 存放选中的 id
const selectedIds = ref([])

const handleSelectionChange = (val) => {
multipleSelection.value = val
selectedIds.value = val.map(item => item.id)
}
</script>

👉 在表格里 @selection-change 事件会把 选中的行对象数组 传回来,你只要 .map(item => item.id) 就能拿到 id。


⚡ 提示:

  • 如果只是复选框列表 → 用 el-checkbox-group v-model 绑定 id 数组。
  • 如果是表格多选 → 用 @selection-change 拿到行数据,再提取 id。

Prompt:.map这是什么

.map()JavaScript 数组对象的一个方法,用来 遍历数组并返回一个新的数组


1. 基本语法

1
2
3
array.map(function(item, index, arr) {
// return 的结果会组成一个新的数组
})
  • item:数组中正在处理的元素
  • index:当前元素的索引
  • arr:原始数组本身
  • 返回值:一个新数组(不会改变原数组)

2. 举个例子

1
2
3
4
5
6
7
const numbers = [1, 2, 3]

// 把每个元素平方
const squares = numbers.map(num => num * num)

console.log(squares) // [1, 4, 9]
console.log(numbers) // [1, 2, 3] 原数组不变

3. 在你 Element Plus 的场景里

假设表格多选返回了这样的数组:

1
2
3
4
const multipleSelection = [
{ id: 1, name: '张三' },
{ id: 3, name: '王五' }
]

如果你只想要 id,就可以用 .map() 提取出来:

1
2
3
const selectedIds = multipleSelection.map(item => item.id)

console.log(selectedIds) // [1, 3]

等价于循环写法:

1
2
3
4
const selectedIds = []
for (let i = 0; i < multipleSelection.length; i++) {
selectedIds.push(multipleSelection[i].id)
}

但是 .map() 写法更简洁,也更常用。

Prompt:怎么获取路由实例

Vue Router 4(Vue 3 配套版本) 里,获取路由实例有两种情况:


1. 在 组合式 API(setup)

使用官方提供的 useRouteruseRoute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
import { useRouter, useRoute } from 'vue-router'

const router = useRouter() // 路由实例(用来跳转、控制导航)
const route = useRoute() // 当前路由对象(包含 path、params、query 等)

// 示例:跳转到某个页面
function goHome() {
router.push('/')
}

// 示例:获取路由参数
console.log(route.params.id)
console.log(route.query.keyword)
</script>

2. 在 选项式 API(Vue 2 风格)

如果你还在用 export default { ... } 这种写法,可以直接用 this.$routerthis.$route

1
2
3
4
5
6
7
8
9
10
export default {
methods: {
goHome() {
this.$router.push('/')
},
logParams() {
console.log(this.$route.params.id)
}
}
}

📌 总结

  • 组合式 API(setup) → 用 useRouter() / useRoute()
  • 选项式 API → 用 this.$router / this.$route

Prompt:vue怎么把对象转为字符串

在 Vue(其实就是在 JavaScript 里),对象转成字符串常用的方法就是 **JSON.stringify()**。


1. 基本用法

1
2
3
4
const obj = { id: 1, name: '张三' }
const str = JSON.stringify(obj)

console.log(str) // '{"id":1,"name":"张三"}'

这样 str 就是一个 JSON 格式的字符串了。


2. 在 Vue 里用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>
<p>对象转字符串:{{ jsonStr }}</p>
</div>
</template>

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

const user = ref({ id: 1, name: '张三' })

// 直接转换
const jsonStr = computed(() => JSON.stringify(user.value))
</script>

渲染结果:

1
对象转字符串:{"id":1,"name":"张三"}

3. 格式化输出(带缩进)

如果你希望字符串更美观,可以传递参数:

1
JSON.stringify(obj, null, 2)
1
2
3
4
5
6
7
8
9
const obj = { id: 1, name: '张三' }
console.log(JSON.stringify(obj, null, 2))

/* 输出:
{
"id": 1,
"name": "张三"
}
*/

4. 还原成对象

如果你要把字符串转回对象,用 JSON.parse()

1
2
3
4
const str = '{"id":1,"name":"张三"}'
const obj = JSON.parse(str)

console.log(obj.id) // 1

✅ 所以总结就是:

  • 对象 → 字符串JSON.stringify(obj)
  • 字符串 → 对象JSON.parse(str)

Prompt:==和===区别

==(宽松相等)

  • 先进行类型转换,再比较值是否相等。
  • 有时会出现一些“看起来奇怪”的结果。

例子:

1
2
3
4
1 == '1'       // true   (字符串 '1' 转成数字 1)
true == 1 // true (true 转成 1)
false == 0 // true (false 转成 0)
null == undefined // true (规则特殊)

===(严格相等)

  • 不会进行类型转换,必须 类型相同值相同 才为 true。
  • 推荐使用它,结果更可预期。

例子:

1
2
3
4
1 === '1'      // false (类型不同:数字 vs 字符串)
true === 1 // false (布尔 vs 数字)
false === 0 // false
null === undefined // false

📌 总结

  • ==:比较前会自动做类型转换(容易踩坑)
  • ===:不做类型转换(更安全,推荐用)

⚡ 面试答法(简洁版):

== 在比较前会进行隐式类型转换,而 === 会同时比较类型和值,开发中推荐优先使用 === 以避免类型转换带来的意外。


要不要我帮你整理一张 常见 == 的类型转换对照表(比如 [] == false'' == 0 这种奇怪情况)?

Prompt:前端项目的打包部署

前端项目的 打包部署 大体上分成两个阶段:


一、打包 (Build)

前端项目(Vue、React、Angular…)开发时通常是运行在 开发服务器 (npm run dev / vite dev / vue-cli-service serve),但是 部署上线需要静态文件(HTML、JS、CSS 等)。

1. 安装依赖

1
npm install

2. 打包构建

  • 如果是 Vue CLI 项目:
    1
    npm run build
    会生成一个 dist/ 文件夹,里面是压缩优化后的 index.htmljs/css/ 等静态资源。
  • 如果是 Vite 项目:
    1
    npm run build
    默认也会生成 dist/
  • 如果是 **React (CRA)**:
    1
    npm run build
    会生成 build/

二、部署 (Deploy)

1. 部署到静态服务器

直接把 dist/ 目录放到服务器即可:

  • Nginx
    1
    2
    3
    4
    5
    6
    7
    8
    9
    server {
    listen 80;
    server_name mysite.com;
    root /var/www/mysite/dist;
    index index.html;
    location / {
    try_files $uri $uri/ /index.html;
    }
    }

    ⚠️ try_files 很重要,做 SPA 前端路由时避免刷新 404。

  • Apache / IIS → 也可以配置虚拟目录,指向 dist/

2. 部署到静态托管平台

  • GitHub Pages:适合个人小项目。
  • Vercel / Netlify:支持自动构建 + 部署。
  • 阿里云 OSS / 腾讯云 COS:上传 dist/ 静态文件即可。
  • Firebase Hosting:一键发布。

3. Docker 部署(进阶)

如果你用 Docker,可以把前端项目打包后放进 Nginx 镜像:

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
# 使用 node 构建阶段
FROM node:18 AS build
WORKDIR /app
COPY . .
RUN npm install && npm run build

# 使用 nginx 部署阶段
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

构建并运行:

1
2
docker build -t my-frontend .
docker run -d -p 80:80 my-frontend

三、流程总结

  1. 开发环境npm run dev
  2. 打包构建npm run build → 生成 dist/
  3. 上传部署:Nginx / Apache / 静态托管 / Docker
  4. 访问测试:打开域名或 IP 验证是否正常

Prompt:总结一下学了什么

一、Vue 基础与进阶

  1. watch 侦听
    • Vue2 的 watch 基本用法、deep 深度侦听、immediate 立即执行、监听计算属性或路径。
    • Vue3 的 watchwatch(source, callback, options)、监听单个/多个属性、深度侦听、立即执行。
    • watchEffect:自动收集依赖,简化监听逻辑。
    • 监听对象属性:推荐用 getter,如 watch(() => user.value.age, callback)
  2. computed vs watch
    • computed:用于派生数据(缓存)。
    • watch:用于副作用(异步请求、本地存储、复杂逻辑)。

二、模块导入导出

  • import xxx from ... → 需要 export default
  • import { foo } from ... → 对应 export function fooexport const foo
  • 错误 does not provide an export named 'default' 说明模块没有默认导出。

三、Element Plus 使用

  1. 复选框获取数据 id
    • 普通 el-checkbox-group:用 :label="item.id" → 选中的数组就是 id。
    • 表格多选 el-table-column type="selection":在 @selection-change 里用 .map(item => item.id) 提取 id。
  2. .map() 方法
    • 遍历数组并返回新数组。
    • 示例:arr.map(item => item.id) 相当于从对象数组提取所有 id。

四、路由操作

  • Vue3 组合式 API:useRouter()useRoute()
  • 选项式 APIthis.$routerthis.$route

五、对象与字符串

  • 对象转字符串:JSON.stringify(obj),可选缩进参数 JSON.stringify(obj, null, 2)
  • 字符串转对象:JSON.parse(str)

六、JavaScript 基础

  1. == vs ===
    • ==:宽松相等,会类型转换。
    • ===:严格相等,不转换类型,推荐使用。
  2. 常见隐式转换1 == '1' → truetrue == 1 → truenull == undefined → true

七、前端项目打包部署

  1. 打包
    • npm run build → 生成 dist/(Vue、Vite、React)。
  2. 部署
    • 静态服务器:Nginx / Apache。
    • 托管平台:GitHub Pages / Vercel / Netlify / OSS / Firebase。
    • Docker 部署:Node 构建 → Nginx 托管。
  3. Nginx 配置try_files $uri $uri/ /index.html; 解决 SPA 刷新 404。

✅ 总结起来,你已经学习了:

  • Vue2 & Vue3 中 watch 的用法与区别
  • 如何监听对象属性
  • JS 模块导入导出的区别(default vs 具名)
  • Element Plus 复选框和表格选中获取 id 的方法
  • .map() 的作用与替代写法
  • Vue Router 获取路由实例的方法
  • 对象与字符串的互转(JSON)
  • ===== 的区别
  • 前端项目从打包到部署的完整流程