Vue.js 开发指南

渐进式 JavaScript 框架,构建现代化用户界面

1. 简介

Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它被设计为可以自底向上逐层应用,核心库只关注视图层,易于上手且便于与第三方库或既有项目整合。

渐进式

可以逐步采用,不必重构整个应用

响应式

数据驱动,自动更新视图

组件化

可复用的组件系统

生态丰富

完整的工具链和生态系统

2. 安装和配置

方法一:CDN 引入

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

方法二:npm 安装

npm install vue@next
# 或者
yarn add vue@next

方法三:Vite 创建项目

npm create vue@latest my-vue-app
cd my-vue-app
npm install
npm run dev

3. 基础语法

模板语法

<div id="app">
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
    <button @click="handleClick">点击我</button>
</div>

<script>
const { createApp } = Vue;

createApp({
    data() {
        return {
            title: '欢迎使用 Vue.js',
            message: '这是一个简单的示例'
        }
    },
    methods: {
        handleClick() {
            this.message = '按钮被点击了!';
        }
    }
}).mount('#app');
</script>

数据绑定

<!-- 文本插值 -->
<span>{{ msg }}</span>

<!-- 属性绑定 -->
<img :src="imageSrc" :alt="imageAlt">

<!-- 双向绑定 -->
<input v-model="inputValue">

<!-- 条件渲染 -->
<p v-if="isVisible">这段文字是可见的</p>
<p v-else>这段文字是隐藏的</p>

<!-- 列表渲染 -->
<ul>
    <li v-for="item in items" :key="item.id">
        {{ item.name }}
    </li>
</ul>

4. 组件系统

单文件组件

<!-- UserCard.vue -->
<template>
    <div class="user-card">
        <img :src="user.avatar" :alt="user.name">
        <h3>{{ user.name }}</h3>
        <p>{{ user.email }}</p>
        <button @click="sendMessage">发送消息</button>
    </div>
</template>

<script>
export default {
    name: 'UserCard',
    props: {
        user: {
            type: Object,
            required: true
        }
    },
    methods: {
        sendMessage() {
            this.$emit('message-sent', this.user);
        }
    }
}
</script>

<style scoped>
.user-card {
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 20px;
    text-align: center;
}

.user-card img {
    width: 80px;
    height: 80px;
    border-radius: 50%;
}
</style>

Props 和 Events

<!-- 父组件 -->
<template>
    <div>
        <user-card 
            v-for="user in users" 
            :key="user.id"
            :user="user"
            @message-sent="handleMessageSent"
        ></user-card>
    </div>
</template>

<script>
import UserCard from './UserCard.vue';

export default {
    components: {
        UserCard
    },
    data() {
        return {
            users: [
                { id: 1, name: '张三', email: 'zhangsan@example.com', avatar: '/avatars/1.jpg' },
                { id: 2, name: '李四', email: 'lisi@example.com', avatar: '/avatars/2.jpg' }
            ]
        }
    },
    methods: {
        handleMessageSent(user) {
            console.log('发送消息给:', user.name);
        }
    }
}
</script>

5. 指令

v-if / v-else

条件渲染

<div v-if="isLoggedIn">
    欢迎回来!
</div>
<div v-else>
    请先登录
</div>

v-for

列表渲染

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

v-model

双向绑定

<input v-model="message">
<textarea v-model="content"></textarea>
<select v-model="selected">
    <option value="a">A</option>
    <option value="b">B</option>
</select>

v-on (@)

事件监听

<button @click="handleClick">点击</button>
<input @keyup.enter="handleEnter">
<div @mouseover="handleHover">悬停</div>

6. 生命周期

创建阶段

  • beforeCreate - 实例初始化之前
  • created - 实例创建完成

挂载阶段

  • beforeMount - 挂载开始之前
  • mounted - 挂载完成

更新阶段

  • beforeUpdate - 数据更新之前
  • updated - 数据更新完成

销毁阶段

  • beforeUnmount - 销毁之前
  • unmounted - 销毁完成
export default {
    data() {
        return {
            message: 'Hello Vue!'
        }
    },
    
    beforeCreate() {
        console.log('beforeCreate: 实例初始化之前');
    },
    
    created() {
        console.log('created: 实例创建完成');
        // 可以访问 data 和 methods
        console.log(this.message);
    },
    
    beforeMount() {
        console.log('beforeMount: 挂载开始之前');
    },
    
    mounted() {
        console.log('mounted: 挂载完成');
        // 可以访问 DOM 元素
        console.log(this.$refs.myElement);
    },
    
    beforeUpdate() {
        console.log('beforeUpdate: 数据更新之前');
    },
    
    updated() {
        console.log('updated: 数据更新完成');
    },
    
    beforeUnmount() {
        console.log('beforeUnmount: 销毁之前');
        // 清理定时器、取消订阅等
    },
    
    unmounted() {
        console.log('unmounted: 销毁完成');
    }
}

7. 组合式 API

Vue 3 引入了组合式 API,提供了更灵活的代码组织方式和更好的 TypeScript 支持。

<template>
    <div>
        <h2>计数器: {{ count }}</h2>
        <button @click="increment">+1</button>
        <button @click="decrement">-1</button>
        <button @click="reset">重置</button>
        
        <p>用户信息: {{ user.name }} - {{ user.email }}</p>
    </div>
</template>

<script>
import { ref, reactive, computed, watch, onMounted } from 'vue';

export default {
    setup() {
        // 响应式数据
        const count = ref(0);
        const user = reactive({
            name: '张三',
            email: 'zhangsan@example.com'
        });
        
        // 计算属性
        const doubleCount = computed(() => count.value * 2);
        
        // 方法
        const increment = () => count.value++;
        const decrement = () => count.value--;
        const reset = () => count.value = 0;
        
        // 监听器
        watch(count, (newValue, oldValue) => {
            console.log(`计数从 ${oldValue} 变为 ${newValue}`);
        });
        
        // 生命周期钩子
        onMounted(() => {
            console.log('组件已挂载');
        });
        
        // 返回模板中需要的数据和方法
        return {
            count,
            user,
            doubleCount,
            increment,
            decrement,
            reset
        };
    }
}
</script>

8. 路由

安装 Vue Router

npm install vue-router@4

路由配置

// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
import User from '../views/User.vue';

const routes = [
    {
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/about',
        name: 'About',
        component: About
    },
    {
        path: '/user/:id',
        name: 'User',
        component: User,
        props: true
    },
    {
        path: '/dashboard',
        name: 'Dashboard',
        component: () => import('../views/Dashboard.vue'), // 懒加载
        meta: { requiresAuth: true }
    }
];

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

// 路由守卫
router.beforeEach((to, from, next) => {
    if (to.meta.requiresAuth) {
        // 检查用户是否已登录
        const isAuthenticated = checkAuth();
        if (!isAuthenticated) {
            next('/login');
        } else {
            next();
        }
    } else {
        next();
    }
});

export default router;

使用路由

<template>
    <nav>
        <router-link to="/">首页</router-link>
        <router-link to="/about">关于</router-link>
        <router-link :to="{ name: 'User', params: { id: userId } }">
            用户详情
        </router-link>
    </nav>
    
    <router-view></router-view>
</template>

<script>
import { useRouter, useRoute } from 'vue-router';

export default {
    setup() {
        const router = useRouter();
        const route = useRoute();
        
        const goToUser = (userId) => {
            router.push({ name: 'User', params: { id: userId } });
        };
        
        const goBack = () => {
            router.go(-1);
        };
        
        return {
            goToUser,
            goBack,
            currentRoute: route
        };
    }
}
</script>

9. 状态管理 (Pinia)

安装 Pinia

npm install pinia

创建 Store

// stores/user.js
import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
    state: () => ({
        user: null,
        isLoggedIn: false,
        preferences: {
            theme: 'light',
            language: 'zh-CN'
        }
    }),
    
    getters: {
        userName: (state) => state.user?.name || '游客',
        isAdmin: (state) => state.user?.role === 'admin'
    },
    
    actions: {
        async login(credentials) {
            try {
                const response = await authAPI.login(credentials);
                this.user = response.data.user;
                this.isLoggedIn = true;
                return { success: true };
            } catch (error) {
                return { success: false, error: error.message };
            }
        },
        
        logout() {
            this.user = null;
            this.isLoggedIn = false;
            authAPI.logout();
        },
        
        updatePreferences(newPreferences) {
            this.preferences = { ...this.preferences, ...newPreferences };
        }
    }
});

// stores/counter.js
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', () => {
    const count = ref(0);
    
    const increment = () => {
        count.value++;
    };
    
    const decrement = () => {
        count.value--;
    };
    
    const reset = () => {
        count.value = 0;
    };
    
    return {
        count,
        increment,
        decrement,
        reset
    };
});

在组件中使用 Store

<template>
    <div>
        <h2>欢迎,{{ userName }}!</h2>
        <p>计数器:{{ count }}</p>
        
        <button @click="increment">+1</button>
        <button @click="decrement">-1</button>
        <button @click="reset">重置</button>
        
        <button v-if="!isLoggedIn" @click="showLogin">登录</button>
        <button v-else @click="logout">退出</button>
    </div>
</template>

<script>
import { useUserStore } from '@/stores/user';
import { useCounterStore } from '@/stores/counter';

export default {
    setup() {
        const userStore = useUserStore();
        const counterStore = useCounterStore();
        
        const showLogin = () => {
            // 显示登录对话框
        };
        
        return {
            // 解构 store
            ...userStore,
            ...counterStore
        };
    }
}
</script>

10. 构建和部署

Vite 构建配置

// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';

export default defineConfig({
    plugins: [vue()],
    resolve: {
        alias: {
            '@': resolve(__dirname, 'src')
        }
    },
    build: {
        outDir: 'dist',
        sourcemap: true,
        rollupOptions: {
            output: {
                manualChunks: {
                    vendor: ['vue', 'vue-router', 'pinia'],
                    ui: ['element-plus']
                }
            }
        }
    },
    server: {
        port: 3000,
        open: true,
        proxy: {
            '/api': {
                target: 'http://localhost:8080',
                changeOrigin: true,
                rewrite: (path) => path.replace(/^\/api/, '')
            }
        }
    }
});

环境变量配置

# .env.development
VITE_APP_TITLE=Vue 应用 - 开发环境
VITE_API_BASE_URL=http://localhost:8080/api
VITE_APP_VERSION=1.0.0

# .env.production
VITE_APP_TITLE=Vue 应用
VITE_API_BASE_URL=https://api.example.com
VITE_APP_VERSION=1.0.0

部署脚本

{
    "scripts": {
        "dev": "vite",
        "build": "vite build",
        "preview": "vite preview",
        "deploy": "npm run build && npm run upload",
        "upload": "scp -r dist/* user@server:/var/www/html/"
    }
}

学习总结

Vue.js 是一个强大且灵活的前端框架,具有以下核心优势:

  • 渐进式采用 - 可以逐步引入到现有项目中
  • 响应式系统 - 数据变化自动更新视图
  • 组件化开发 - 提高代码复用性和维护性
  • 丰富的生态 - Vue Router、Pinia、Vuetify 等
  • 优秀的开发体验 - 热重载、TypeScript 支持

下一步学习建议:

  1. 深入学习 Vue 3 的组合式 API
  2. 掌握 TypeScript 在 Vue 中的应用
  3. 学习服务端渲染 (Nuxt.js)
  4. 探索移动端开发 (Quasar、Ionic)
  5. 了解测试策略和最佳实践