Skip to content

Vue.js 简介

Vue.js 是一套用于构建用户界面的渐进式框架,基于标准 HTML、CSS 和 JavaScript 构建,提供了声明式组件化的编程模型,帮助你高效地开发用户界面。

Vue.js 的核心特点:

  • 声明式渲染:通过简洁的模板语法描述数据和 DOM 之间的关系
  • 响应式数据绑定:当数据发生变化时,自动更新相关视图
  • 组件化开发:将应用拆分为独立、可复用的组件,每个组件包含自己的状态和逻辑

交互示例

你可以点击下方的按钮来体验 Vue 的响应式特性:

Vue 响应式计数器示例

体验 Vue 3 组合式 API 的响应式特性

当前计数:0
增加次数0
减少次数0
重置次数0
💡
响应式特性演示

点击按钮改变计数器的值,观察视图如何自动更新。Vue 的响应式系统会追踪数据变化并高效地更新 DOM。

 

以上示例的源代码如下:

vue
<template>
  <div class="container">
    <div class="header">
      <h3>Vue 响应式计数器示例</h3>
      <p>体验 Vue 3 组合式 API 的响应式特性</p>
    </div>
    <div class="info">
      <span class="message">{{ message }}</span>
      <span class="separator">:</span>
      <transition name="count" mode="out-in">
        <span :key="count" class="count">{{ count }}</span>
      </transition>
    </div>
    <div class="button-group">
      <el-button type="primary" size="large" @click="increment" :icon="Plus" circle></el-button>
      <el-button type="success" size="large" @click="decrement" :icon="Minus" :disabled="count <= 0" circle></el-button>
      <el-button type="warning" size="large" @click="reset" :icon="Refresh" :disabled="count === 0" circle></el-button>
    </div>
    <div class="stats-row">
      <div class="stat-item">
        <span class="stat-label">增加次数</span>
        <span class="stat-value increment">{{ incrementCount }}</span>
      </div>
      <div class="stat-item">
        <span class="stat-label">减少次数</span>
        <span class="stat-value decrement">{{ decrementCount }}</span>
      </div>
      <div class="stat-item">
        <span class="stat-label">重置次数</span>
        <span class="stat-value reset">{{ resetCount }}</span>
      </div>
    </div>
    <div class="info-card">
      <div class="info-icon">💡</div>
      <div class="info-content">
        <strong>响应式特性演示</strong>
        <p>点击按钮改变计数器的值,观察视图如何自动更新。Vue 的响应式系统会追踪数据变化并高效地更新 DOM。</p>
      </div>
    </div
  </div>
</template>

<script setup>
import { ref } from "vue";
import { Plus, Minus, Refresh } from '@element-plus/icons-vue';

// 定义响应式状态
const message = ref("当前计数");
const count = ref(0);

// 统计数据
const incrementCount = ref(0);
const decrementCount = ref(0);
const resetCount = ref(0);

// 增加计数
const increment = () => {
  count.value++;
  incrementCount.value++;
};

// 减少计数
const decrement = () => {
  if (count.value > 0) {
    count.value--;
    decrementCount.value++;
  }
};

// 重置计数器
const reset = () => {
  if (count.value !== 0) {
    count.value = 0;
    resetCount.value++;
  }
};
</script>

<style scoped>
.container {
  padding: 32px;
  border: 1px solid #e0e4e8;
  border-radius: 16px;
  margin: 24px 0;
  background: #ffffff;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  transition: all 0.3s ease;
}

.container:hover {
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  transform: translateY(-2px);
}

.header {
  text-align: center;
  margin-bottom: 32px;
  padding-bottom: 20px;
  border-bottom: 2px solid #f0f2f5;
}

.header h3 {
  font-size: 1.5rem;
  font-weight: 700;
  color: #1a1a2e;
  margin: 0 0 8px 0;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.header p {
  font-size: 0.95rem;
  color: #6b7280;
  margin: 0;
}

.info {
  text-align: center;
  margin-bottom: 32px;
  font-size: 1.75rem;
  font-weight: 600;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 16px;
  padding: 24px;
  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
  border-radius: 12px;
}

.message {
  color: #6366f1;
}

.separator {
  color: #9ca3af;
}

.count {
  color: #10b981;
  font-size: 3rem;
  font-weight: 800;
  min-width: 80px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* 计数数字动画 */
.count-enter-active {
  animation: countBounceIn 0.3s ease-out;
}

.count-leave-active {
  animation: countBounceOut 0.3s ease-in;
}

@keyframes countBounceIn {
  0% {
    opacity: 0;
    transform: scale(0.5);
  }

  50% {
    transform: scale(1.1);
  }

  100% {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes countBounceOut {
  0% {
    opacity: 1;
    transform: scale(1);
  }

  50% {
    transform: scale(0.9);
  }

  100% {
    opacity: 0;
    transform: scale(0.5);
  }
}

.button-group {
  display: flex;
  justify-content: center;
  gap: 16px;
  margin-bottom: 28px;
}

.button-group .el-button {
  transition: all 0.2s ease;
}

.button-group .el-button:hover:not(:disabled) {
  transform: scale(1.1);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
}

.button-group .el-button:active:not(:disabled) {
  transform: scale(0.95);
}

.info-card {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 20px;
  background: linear-gradient(135deg, #fefce8 0%, #fef9c3 100%);
  border-radius: 12px;
  border-left: 4px solid #f59e0b;
  margin-top: 24px;
}

.info-icon {
  font-size: 1.75rem;
  line-height: 1;
}

.info-content {
  flex: 1;
}

.info-content strong {
  display: block;
  font-size: 1rem;
  color: #92400e;
  margin-bottom: 8px;
}

.info-content p {
  font-size: 0.9rem;
  color: #78350f;
  margin: 0;
  line-height: 1.6;
}

.stats-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.stat-item {
  text-align: center;
  padding: 16px;
  background: #f8fafc;
  border-radius: 10px;
  transition: all 0.2s ease;
}

.stat-item:hover {
  background: #f1f5f9;
  transform: translateY(-2px);
}

.stat-label {
  display: block;
  font-size: 0.85rem;
  color: #6b7280;
  margin-bottom: 8px;
}

.stat-value {
  font-size: 1.5rem;
  font-weight: 700;
  transition: color 0.2s ease;
}

.stat-value.increment {
  color: #10b981;
}

.stat-value.decrement {
  color: #f59e0b;
}

.stat-value.reset {
  color: #ef4444;
}

/* 响应式设计 */
@media (max-width: 640px) {
  .container {
    padding: 20px;
    margin: 16px 0;
  }

  .info {
    font-size: 1.25rem;
    padding: 16px;
  }

  .count {
    font-size: 2.25rem;
    min-width: 60px;
  }

  .button-group {
    gap: 12px;
  }

  .stats-row {
    grid-template-columns: 1fr;
    gap: 12px;
  }
}
</style>

渐进式框架

Vue 是一个框架,也是一个生态。Vue 的设计非常注重灵活性和"可以被逐步集成"这个特点。

  1. 无需构建步骤,渐进式增强静态的 HTML
  2. 在任何页面中作为 Web Components 嵌入
  3. 单页应用 (SPA)
  4. 全栈 / 服务端渲染 (SSR)
  5. Jamstack / 静态站点生成 (SSG)
  6. 开发桌面端、移动端、WebGL,甚至是命令行终端中的界面

单文件组件

Vue 使用类似 HTML 格式的文件来书写组件,这种文件被称为单文件组件 (也被称为 *.vue 文件,英文 Single-File Components,缩写为 SFC)。

Vue 的单文件组件会将一个组件的逻辑 (JavaScript),模板 (HTML) 和样式 (CSS) 封装在同一个文件里。

API 风格

Vue 提供了两种不同的 API 风格:

  • 选项式 API:使用包含多个选项的对象来描述组件的逻辑。每个选项都有其特定的功能,如 datamethodscomputed 等。
  • 组合式 API:使用基于函数的 API,通过调用 Vue 提供的函数来定义组件的逻辑。组合式 API 更加强大和灵活,特别适用于大型组件和复杂的逻辑。

选项式 API (Options API)

选项式 API 是 Vue 最早引入的 API 风格,它使用一个包含多个选项的对象来描述组件的逻辑。每个选项都有其特定的功能,如 datamethodscomputed 等。

以下是一个简单的选项式 API 组件示例:

vue
<template>
  <div>
    <h1>{{ message }}</h1>
    <p>当前计数:{{ count }}</p>
    <button @click="add">增加</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue',
      count: 0
    }
  },
  methods: {
    add() {
      this.count++
    }
  }
}
</script>

组合式 API (Composition API)

组合式 API 是 Vue 3 引入的新 API 风格,它使用基于函数的 API,通过调用 Vue 提供的函数来定义组件的逻辑。组合式 API 更加强大和灵活,特别适用于大型组件和复杂的逻辑。

通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup> 搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。

以下是一个简单的组合式 API 组件示例:

vue
<template>
  <div>
    <h1>{{ message }}</h1>
    <p>当前计数:{{ count }}</p>
    <button @click="add">增加</button>
  </div>
</template>

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

const message = ref('Hello Vue')
const count = ref(0)

function add() {
  count.value++
}
</script>