Vue 3 入门指南:从基础到实战 (组合式API版)

Vue 3 入门指南:从基础到实战

模板语法:构建动态页面

Vue 3 使用简单直观的模板语法,让你轻松构建动态 HTML 页面。

插值表达式

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
  </div>
</template>

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

const title = ref('欢迎来到 Vue 3 世界')
const message = ref('开始你的前端之旅吧!')
</script>

指令:v-bind 和 v-on

<template>
  <button v-bind:class="{ active: isActive }" v-on:click="handleClick">
    点击我
  </button>
</template>

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

const isActive = ref(false)

const handleClick = () => {
  isActive.value = !isActive.value
}
</script>

条件渲染:v-if 和 v-else

<template>
  <div v-if="showGreeting">
    <h1>欢迎回来!</h1>
  </div>
  <div v-else>
    <h1>请登录</h1>
  </div>
</template>

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

const showGreeting = ref(true)
</script>

列表渲染:v-for

<template>
  <ul>
    <li v-for="(item, index) in items" :key="index">
      {{ item }}
    </li>
  </ul>
</template>

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

const items = ref(['苹果', '香蕉', '橘子'])
</script>

侦听器:监听数据变化

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

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

const count = ref(0)

const increment = () => {
  count.value++
}

watch(count, (newCount, oldCount) => {
  console.log(`计数器从 ${oldCount} 变为 ${newCount}`)
})
</script>

计算属性:简化复杂逻辑

<template>
  <p>商品总价:{{ totalPrice }}</p>
</template>

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

const price = ref(100)
const quantity = ref(2)

const totalPrice = computed(() => {
  return price.value * quantity.value
})
</script>

组件:构建可复用模块

注册组件

<template>
  <MyComponent message="欢迎使用组件!" />
</template>

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

父组件向子组件传值

<!-- MyComponent.vue -->
<template>
  <div>
    <h1>{{ message }}</h1>
  </div>
</template>

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

const props = defineProps(['message'])
</script>

子组件向父组件传值

<!-- Child.vue -->
<template>
  <button @click="emitClick">点击我</button>
</template>

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

const emit = defineEmits()
const emitClick = () => {
  emit('childClick')
}
</script>

<!-- Parent.vue -->
<template>
  <Child @childClick="handleClick" />
</template>

<script setup>
const handleClick = () => {
  console.log('子组件被点击了!')
}
</script>

透传属性和事件

<!-- Child.vue -->
<template>
  <div v-bind="$attrs" @click="$emit('click', $event)">
    {{ message }}
  </div>
</template>

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

const props = defineProps(['message'])
</script>

<!-- Parent.vue -->
<template>
  <Child :message="greeting" class="my-class" @click="handleClick" />
</template>

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

const greeting = ref('你好!')
const handleClick = (event) => {
  console.log('Child 组件被点击了!', event)
}
</script>

插槽:定制组件内容

<!-- Child.vue -->
<template>
  <div>
    <slot />
  </div>
</template>

<!-- Parent.vue -->
<template>
  <Child>
    <p>这是自定义内容,插入到插槽中</p>
  </Child>
</template>

依赖注入:共享数据和方法

<!--  main.js  -->
import { createApp } from 'vue'
import App from './App.vue'
import MyService from './MyService.js'

const app = createApp(App)
app.provide('myService', new MyService())
app.mount('#app')

<!-- MyService.js -->
export default class MyService {
  getMessage() {
    return '来自依赖注入服务的欢迎信息!'
  }
}

<!-- App.vue -->
<template>
  <div>{{ message }}</div>
</template>

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

const myService = inject('myService')
const message = myService.getMessage()
</script>

模板引用:访问DOM元素

v-ref

<template>
  <input type="text" v-model="name" ref="inputRef" />
  <button @click="focusInput">聚焦输入框</button>
</template>

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

const name = ref('')
const inputRef = ref(null)

const focusInput = () => {
  inputRef.value.focus()
}
</script>

v-for 中的模板引用

<template>
  <ul>
    <li v-for="(item, index) in items" :key="index" ref="listItemRefs">
      {{ item }}
    </li>
  </ul>
</template>

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

const items = ref(['苹果', '香蕉', '橘子'])
const listItemRefs = ref([])

onMounted(() => {
  console.log(listItemRefs.value[0]) // 访问第一个列表项
})
</script>

组件上的 ref

<!-- Child.vue -->
<template>
  <div ref="childRef">{{ message }}</div>
</template>

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

const props = defineProps(['message'])
</script>

<!-- Parent.vue -->
<template>
  <Child ref="childComponent" message="来自父组件的信息" />
</template>

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

const childComponent = ref(null)

onMounted(() => {
  console.log(childComponent.value.$refs.childRef)
})
</script>

路由:构建单页面应用

快速使用

<!--  main.js  -->
import { createApp } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import App from './App.vue'
import Home from './components/Home.vue'
import About from './components/About.vue'

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

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

<!--  App.vue  -->
<template>
  <div id="app">
    <router-link to="/">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-view />
  </div>
</template>

重定向路由

const routes = [
  { path: '/', redirect: '/home' }, // 重定向到 '/home'
]

嵌套路由

const routes = [
  {
    path: '/products',
    component: Products,
    children: [
      { path: ':id', component: ProductDetails } // 商品详情
    ]
  }
]

路径参数

<!-- ProductDetails.vue -->
<template>
  <div>
    <h1>商品详情:{{ $route.params.id }}</h1>
  </div>
</template>

声明式与编程式导航

<!-- 使用 router-link 进行声明式导航 -->
<template>
  <router-link to="/about">关于</router-link>
</template>

<!-- 编程式导航 -->
<template>
  <button @click="goHome">返回首页</button>
</template>

<script setup>
import { useRouter } from 'vue-router'

const router = useRouter()
const goHome = () => {
  router.push('/')
}
</script>

导航守卫

const router = createRouter({
  routes,
  beforeEach: (to, from) => {
    if (to.path === '/admin' && !isLoggedIn) {
      return '/login' // 重定向到登录页面
    }
    return true // 允许导航
  }
})

状态管理库 Pinia:集中管理状态

创建 Store

// store.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    doubleCount: (state) => state.count * 2
  },
  actions: {
    increment() {
      this.count++
    }
  }
})

使用 Store

<template>
  <div>
    <p>计数:{{ counter.count }}</p>
    <p>双倍计数:{{ counter.doubleCount }}</p>
    <button @click="counter.increment">增加</button>
  </div>
</template>

<script setup>
import { useCounterStore } from './store'

const counter = useCounterStore()
</script>

网络请求:使用 Axios

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

const posts = ref([])

axios.get('https://jsonplaceholder.typicode.com/posts')
  .then(response => {
    posts.value = response.data
  })
  .catch(error => {
    console.error('请求失败:', error)
  })
</script>

<template>
  <ul>
    <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
  </ul>
</template>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值