似琼碧落

Vue3 学习笔记 - 第一篇:基础入门

发布时间: 2025年7月22日 01:14作者: 似琼碧落浏览: 27 次
已发布

文章摘要

本文是Vue3学习笔记的第一篇,全面介绍Vue3的基础知识和核心特性。从Vue3的简介和主要特性开始,详细讲解了组合式API的使用方法,包括响应式系统、模板语法、事件处理、计算属性和侦听器等核心概念。通过丰富的代码示例和对比表格,帮助读者快速掌握Vue3的基础知识,为后续深入学习打下坚实基础。

内容格式: Markdown字数: 7729 字符

Vue3 简介

Vue3 是 Vue.js 的第三个主要版本,于2020年9月发布。相比Vue2,Vue3带来了许多重要改进:

主要特性

  • 更好的性能: 重写了虚拟DOM,编译时优化,更快的渲染
  • 更小的包体积: 支持tree-shaking,按需打包
  • 更好的TypeScript支持: 从头开始使用TypeScript重写
  • 组合式API: 更灵活的代码组织方式
  • 多个根节点: Fragment支持
  • 新的内置组件: Teleport、Suspense等

Vue3 vs Vue2

特性 Vue2 Vue3
入口API new Vue() createApp()
组件API 选项式API 组合式API + 选项式API
多根节点
TypeScript 有限支持 完全支持
包大小 ~34KB ~10KB (tree-shaking)

安装与环境配置

使用 Vite 创建项目 (推荐)

# npm
npm create vue@latest my-vue-project

# yarn
yarn create vue my-vue-project

# pnpm
pnpm create vue my-vue-project

通过CDN使用

<script src="https://unpkg.com/vue@next"></script>

项目结构

my-vue-project/
├── public/
├── src/
│   ├── assets/
│   ├── components/
│   ├── views/
│   ├── App.vue
│   └── main.js
├── index.html
├── package.json
└── vite.config.js

创建Vue应用

基本应用结构

// main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)
app.mount('#app')

应用配置

const app = createApp(App)

// 全局属性
app.config.globalProperties.$myGlobalMethod = () => {
  // 方法逻辑
}

// 全局组件
app.component('MyComponent', MyComponent)

// 插件
app.use(router)
app.use(store)

app.mount('#app')

组合式API (Composition API)

组合式API是Vue3最重要的新特性,提供了更灵活的代码组织方式。

setup() 函数

<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">增加</button>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    // 响应式数据
    const count = ref(0)
    
    // 方法
    const increment = () => {
      count.value++
    }
    
    // 返回模板需要的数据和方法
    return {
      count,
      increment
    }
  }
}
</script>

<script setup> 语法糖

<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">增加</button>
  </div>
</template>

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

// 直接声明响应式数据
const count = ref(0)

// 直接声明方法
const increment = () => {
  count.value++
}
</script>

响应式系统

ref() - 基础响应式

import { ref } from 'vue'

// 基本类型响应式
const count = ref(0)
const message = ref('Hello')

// 访问值需要使用 .value
console.log(count.value) // 0
count.value++ // 修改值

reactive() - 对象响应式

import { reactive } from 'vue'

// 对象响应式
const state = reactive({
  count: 0,
  name: 'Vue3',
  nested: {
    value: 'deep'
  }
})

// 直接访问属性
console.log(state.count) // 0
state.count++ // 修改值

ref vs reactive

特性 ref reactive
适用类型 基本类型 + 对象 仅对象
访问方式 .value 直接访问
解构 失去响应性 失去响应性
模板中 自动解包 直接使用

toRef() 和 toRefs()

import { reactive, toRef, toRefs } from 'vue'

const state = reactive({
  foo: 1,
  bar: 2
})

// 转换单个属性为ref
const fooRef = toRef(state, 'foo')

// 转换所有属性为ref
const stateAsRefs = toRefs(state)
const { foo, bar } = stateAsRefs // 解构不会失去响应性

模板语法

文本插值

<template>
  <!-- 基本插值 -->
  <p>{{ message }}</p>
  
  <!-- JavaScript表达式 -->
  <p>{{ number + 1 }}</p>
  <p>{{ ok ? 'YES' : 'NO' }}</p>
  <p>{{ message.split('').reverse().join('') }}</p>
</template>

指令

<template>
  <!-- v-bind 属性绑定 -->
  <div v-bind:id="dynamicId"></div>
  <div :id="dynamicId"></div> <!-- 简写 -->
  
  <!-- v-if 条件渲染 -->
  <p v-if="seen">现在你看到我了</p>
  
  <!-- v-for 列表渲染 -->
  <li v-for="item in items" :key="item.id">
    {{ item.text }}
  </li>
  
  <!-- v-on 事件监听 -->
  <button v-on:click="doSomething">点击</button>
  <button @click="doSomething">点击</button> <!-- 简写 -->
</template>

双向绑定

<template>
  <!-- 表单输入绑定 -->
  <input v-model="message" />
  <textarea v-model="text"></textarea>
  
  <!-- 复选框 -->
  <input type="checkbox" v-model="checked" />
  
  <!-- 单选框 -->
  <input type="radio" v-model="picked" value="a" />
  <input type="radio" v-model="picked" value="b" />
  
  <!-- 选择框 -->
  <select v-model="selected">
    <option disabled value="">请选择</option>
    <option>A</option>
    <option>B</option>
  </select>
</template>

事件处理

基本事件处理

<template>
  <!-- 内联处理器 -->
  <button @click="count++">增加 1</button>
  
  <!-- 方法处理器 -->
  <button @click="greet">问候</button>
  
  <!-- 内联调用方法 -->
  <button @click="say('hello')">Say hello</button>
  <button @click="say('bye')">Say bye</button>
</template>

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

const count = ref(0)

const greet = (event) => {
  alert('Hello!')
  console.log(event.target.tagName)
}

const say = (message) => {
  alert(message)
}
</script>

事件修饰符

<template>
  <!-- 阻止默认行为 -->
  <form @submit.prevent="onSubmit"></form>
  
  <!-- 阻止事件冒泡 -->
  <div @click.stop="doThis"></div>
  
  <!-- 修饰符可以串联 -->
  <a @click.stop.prevent="doThat"></a>
  
  <!-- 只有修饰符 -->
  <form @submit.prevent></form>
  
  <!-- 添加事件监听器时使用事件捕获模式 -->
  <div @click.capture="doThis">...</div>
  
  <!-- 只触发一次 -->
  <button @click.once="doThis">Click me</button>
</template>

按键修饰符

<template>
  <!-- 只有在 key 是 Enter 时调用 -->
  <input @keyup.enter="submit" />
  
  <!-- Alt + Enter -->
  <input @keyup.alt.enter="clear" />
  
  <!-- Ctrl + Click -->
  <div @click.ctrl="doSomething">Do something</div>
</template>

计算属性与侦听器

computed() 计算属性

<template>
  <div>
    <p>原始消息: {{ message }}</p>
    <p>反转消息: {{ reversedMessage }}</p>
    <p>作者: {{ author.name }}</p>
    <p>已发布的书籍:</p>
    <span>{{ publishedBooksMessage }}</span>
  </div>
</template>

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

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

// 只读计算属性
const reversedMessage = computed(() => {
  return message.value.split('').reverse().join('')
})

// 可写计算属性
const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  get() {
    return firstName.value + ' ' + lastName.value
  },
  set(newValue) {
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})

const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
</script>

watch() 侦听器

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

const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')

// 侦听单个ref
watch(question, async (newQuestion, oldQuestion) => {
  if (newQuestion.indexOf('?') > -1) {
    answer.value = 'Thinking...'
    try {
      const res = await fetch('https://yesno.wtf/api')
      answer.value = (await res.json()).answer
    } catch (error) {
      answer.value = 'Error! Could not reach the API. ' + error
    }
  }
})

// 侦听多个源
const x = ref(0)
const y = ref(0)

watch([x, y], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})

// 侦听reactive对象
const obj = reactive({ count: 0 })

watch(
  () => obj.count,
  (count) => {
    console.log(`count is: ${count}`)
  }
)

// 深度侦听
watch(
  obj,
  (newValue, oldValue) => {
    // 在嵌套的属性变更时触发
  },
  { deep: true }
)

// 立即执行
watch(
  question,
  (newQuestion) => {
    // 立即执行一次,然后在question改变时再次执行
  },
  { immediate: true }
)
</script>

watchEffect()

import { ref, watchEffect } from 'vue'

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

watchEffect(async () => {
  // 自动跟踪依赖
  const response = await fetch(`/api/todos/${todoId.value}`)
  data.value = await response.json()
})

// 停止侦听
const stop = watchEffect(() => {
  // 副作用
})

// 当不再需要时停止侦听器
stop()

总结

这是Vue3学习笔记的第一部分,涵盖了:

  • Vue3的基本概念和特性
  • 组合式API的使用
  • 响应式系统
  • 模板语法和指令
  • 事件处理
  • 计算属性和侦听器

在下一部分笔记中,我们将学习:

  • 组件基础和组件通信
  • 生命周期钩子
  • 组件插槽
  • 状态管理
  • 路由等高级主题

继续学习,掌握Vue3的强大功能!

分类:
vue3
最后更新: 2025年11月14日 11:58