Vue 项目开发必备知识点

Vue 项目开发必备知识点

本文档系统整理了Vue开发中的核心概念、技术要点和最佳实践,涵盖从基础到高级的各个方面,帮助开发者全面掌握Vue技术栈。

目录导航

  • 1. Vue 核心概念
    • Vue 实例
    • 模板语法
    • 组件系统
    • 响应式原理
  • 2. Vue 组件通信
    • 父组件向子组件传递数据
    • 子组件向父组件传递数据
    • 兄弟组件间通信
    • 跨多层组件通信
    • 非父子组件通信的其他方式
  • 3. Vue 生命周期
    • 生命周期概述
    • 创建阶段
    • 挂载阶段
    • 更新阶段
    • 销毁阶段
    • Vue 3 生命周期变化
  • 4. Vue Router
    • 路由配置与注册
    • 动态路由
    • 嵌套路由
    • 路由参数传递与获取
    • 导航守卫
    • 路由懒加载
    • Vue Router高级特性
  • 5. Vuex/Pinia 状态管理
    • Vuex 核心概念
    • Pinia 核心概念
    • Vuex 与 Pinia 的区别与选择
    • 状态持久化
    • 高级特性与最佳实践
  • 6. Vue 生态系统
    • UI组件库
    • 构建工具
    • HTTP请求
    • 测试工具
    • 其他生态工具
  • 7. Vue 3 新特性
    • 组合式API (***position API)
    • Teleport
    • Suspense
    • ***position API vs Options API
    • 其他Vue 3新特性
  • 8. 性能优化
    • 组件懒加载
    • 虚拟列表
    • 缓存策略
    • 图片优化
    • 渲染优化
    • 打包优化
    • 网络优化
    • 运行时优化
    • Vue 3特有优化
  • 9. Vue移动端开发特别注意事项
    • 触摸事件处理
    • 响应式布局
    • 性能优化
    • 用户体验优化
    • 适配问题
    • 常用库推荐
  • 10. Vue 最佳实践
    • 项目结构组织
    • 组件设计原则
    • 代码规范与质量
    • 性能最佳实践
    • 测试与调试技巧
    • 可维护性考虑
    • 部署与发布策略
  • 11. Vue 表单处理
    • 表单绑定
    • 表单验证
    • 自定义表单控件
    • 表单状态管理
  • 12. Vue 动画与过渡
    • 过渡类与效果
    • 动画钩子函数
    • 列表过渡
    • 第三方动画库集成
  • 13. Vue SSR 与 SSG
    • SSR 基本原理
    • Nuxt.js 框架
    • SSG 静态站点生成
    • SSR/SSG 性能优化
  • 14. Vue 微前端方案
    • 微前端架构
    • 常用微前端框架
    • Vue 与微前端集成
    • 微前端部署策略
  • 15. Vue 国际化 (i18n)
    • Vue I18n 插件
    • 多语言资源管理
    • 国际化最佳实践
    • 日期、数字与货币格式化

1. Vue 核心概念

  • Vue 实例

    • 实例创建:new Vue({/* 配置选项 */})
    • 配置选项:data、methods、***puted、watch、props、***ponents、生命周期钩子等
    • 实例属性与方法:$data$props$el$mount$nextTick$forceUpdate
    • 实例与组件的关系
  • 模板语法

    • 插值表达式:{ { message }},支持JavaScript表达式
    • 指令系统:v-bindv-modelv-forv-if/v-elsev-onv-show
    • 指令修饰符:.stop.prevent.once.lazy.number.trim
    • 计算属性:带缓存的响应式属性,基于依赖自动计算
    • 监听器:对数据变化做出响应的方法

    代码示例:模板语法与指令

    <!-- 插值表达式 -->
    <p>{
        
        { message }}</p>
    <p>{
        
        { count + 1 }}</p>
    <p>{
        
        { isActive ? 'Active' : 'Inactive' }}</p>
    
    <!-- 指令示例 -->
    <div v-if="isVisible">Visible content</div>
    <div v-else>Hidden content</div>
    
    <ul>
      <li v-for="item in items" :key="item.id">
        {
        
        { item.name }}
      </li>
    </ul>
    
    <input v-model="username" placeholder="Enter your name">
    <button v-on:click="submitForm">Submit</button>
    
    <!-- 指令简写 -->
    <img :src="imageUrl" alt="Product">
    <button @click="handleClick">Click me</button>
    
    <!-- 计算属性与监听器 -->
    <div>
      <p>Original price: {
        
        { price }}</p>
      <p>Discounted price: {
        
        { discountedPrice }}</p> <!-- 计算属性 -->
    </div>
    
    // 计算属性与监听器示例
    const vm = new Vue({
         
         
      data() {
         
         
        return {
         
         
          price: 100,
          discount: 0.2,
          username: ''
        }
      },
      ***puted: {
         
         
        // 计算属性 - 有缓存,只有依赖变化时才会重新计算
        discountedPrice() {
         
         
          return this.price * (1 - this.discount);
        }
      },
      watch: {
         
         
        // 监听器 - 响应数据变化
        username(newValue, oldValue) {
         
         
          console.log(`Username changed from ${
           
           oldValue} to ${
           
           newValue}`);
        }
      }
    });
    
  • 组件系统

    • 组件注册:全局注册(Vue.***ponent)和局部注册
    • Props:父子组件间数据传递,支持类型校验和默认值
    • 自定义事件:子组件通过$emit触发事件,父组件通过v-on监听
    • 插槽:默认插槽、具名插槽、作用域插槽
    • 动态组件:***ponent元素和:is属性实现组件动态切换

    代码示例:组件创建与注册

    // 全局组件注册
    Vue.***ponent('global-button', {
         
         
      props: {
         
         
        type: {
         
         
          type: String,
          default: 'primary'
        },
        disabled: {
         
         
          type: Boolean,
          default: false
        }
      },
      template: `
        <button 
          :class="['btn', 'btn-' + type]" 
          :disabled="disabled"
          @click="handleClick"
        >
          <slot>Button</slot>
        </button>
      `,
      methods: {
         
         
        handleClick() {
         
         
          if (!this.disabled) {
         
         
            this.$emit('click');
          }
        }
      }
    });
    
    // 局部组件定义
    const Local***ponent = {
         
         
      template: `
        <div class="local-***ponent">
          <h3>{
          
          { title }}</h3>
          <p>{
          
          { content }}</p>
        </div>
      `,
      props: ['title', 'content']
    };
    
    // 在父组件中使用局部组件
    const Parent***ponent = {
         
         
      ***ponents: {
         
         
        'local-***ponent': Local***ponent
      },
      template: `
        <div class="parent">
          <h2>Parent ***ponent</h2>
          <local-***ponent 
            title="Local ***ponent Title"
            content="Local ***ponent content goes here"
          />
          <global-button @click="handleButtonClick">Global Button</global-button>
        </div>
      `,
      methods: {
         
         
        handleButtonClick() {
         
         
          console.log('Button clicked!');
        }
      }
    };
    

    代码示例:Vue 单文件组件 (SFC)

    <!-- My***ponent.vue -->
    <template>
      <div class="my-***ponent">
        <h2>{
        
        { title }}</h2>
        <p>{
        
        { description }}</p>
        <slot name="content"></slot>
        <slot name="footer" :count="items.length"></slot>
      </div>
    </template>
    
    <script>
    export default {
      name: 'My***ponent',
      props: {
        title: {
          type: String,
          required: true
        },
        description: {
          type: String,
          default: ''
        },
        items: {
          type: Array,
          default: () => []
        }
      }
    };
    </script>
    
    <style scoped>
    .my-***ponent {
      padding: 20px;
      border: 1px solid #eee;
    }
    
    h2 {
      color: #333;
    }
    </style>
    

    代码示例:使用插槽

    <template>
      <div>
        <my-***ponent 
          title="***ponent with Slots"
          description="This ***ponent demonstrates slot usage"
          :items="listItems"
        >
          <!-- 默认插槽内容 -->
          <p>This is content for the default slot.</p>
          
          <!-- 具名插槽内容 -->
          <template v-slot:content>
            <ul>
              <li v-for="item in listItems" :key="item.id">{
        
        { item.name }}</li>
            </ul>
          </template>
          
          <!-- 作用域插槽内容 -->
          <template v-slot:footer="slotProps">
            <p>Total items: {
        
        { slotProps.count }}</p>
          </template>
        </my-***ponent>
      </div>
    </template>
    
    <script>
    import My***ponent from './My***ponent.vue';
    
    export default {
           
           
      ***ponents: {
           
           
        My***ponent
      },
      data() {
           
           
        return {
           
           
          listItems: [
            {
           
            id: 1, name: 'Item 1' },
            {
           
            id: 2, name: 'Item 2' },
            {
           
            id: 3, name: 'Item 3' }
          ]
        };
      }
    };
    </script>
    
  • 响应式原理

    • 数据绑定:单向数据流和双向绑定
    • 虚拟DOM:Vue的渲染机制和diff算法
    • 响应式更新:依赖收集与派发更新机制
    • Vue 2与Vue 3响应式系统的区别

    代码示例:Vue 2 vs Vue 3 响应式实现对比

    // Vue 2 响应式实现原理简化示例
    function observe(data) {
         
         
      if (!data || typeof data !== 'object') {
         
         
        return;
      }
      
      // 遍历数据对象的所有属性
      Object.keys(data).forEach(key => {
         
         
        let internalValue = data[key];
        
        // 创建依赖收集器
        const dep = new Dep();
        
        // 使用Object.defineProperty劫持属性
        Object.defineProperty(data, key, {
         
         
          enumerable: true,
          configurable: true,
          get() {
         
         
            // 收集依赖(Watcher)
            if (Dep.target) {
         
         
              dep.addSub(Dep.target);
            }
            return internalValue;
          },
          set(newValue) {
         
         
            if (newValue === internalValue) return;
            internalValue = newValue;
            // 通知所有依赖更新
            dep.notify();
          }
        });
        
        // 递归观察嵌套对象
        observe(internalValue);
      });
    }
    
    // Vue 3 响应式实现原理简化示例
    function reactive(target) {
         
         
      return new Proxy(target, {
         
         
        get(target, key, receiver) {
         
         
          const result = Reflect.get(target, key, receiver);
          // 收集依赖
          track(target, key);
          // 递归代理嵌套对象
          if (typeof result === 'object' && result !== null) {
         
         
            return reactive(result);
          }
          return result;
        },
        set(target, key, value, receiver) {
         
         
          const oldValue = target[key];
          const result = Reflect.set(target, key, value, receiver);
          // 只有值发生变化时才触发更新
          if (oldValue !== value) {
         
         
            // 触发更新
            trigger(target, key);
          }
          return result;
        },
        deleteProperty(target, key) {
         
         
          const hasKey = key in target;
          const result = Reflect.deleteProperty(target, key);
          if (hasKey) {
         
         
            // 触发更新
            trigger(target, key, 'delete');
          }
          return result;
        }
      });
    }
    
    // Vue 3 中的响应式API使用示例
    const {
         
          ref, reactive, ***puted, watch, watchEffect } = Vue;
    
    const count = ref(0);
    console.log(count.value); // 0
    count.value++; // 触发更新
    
    const user = reactive({
         
         
      name: 'John',
      age: 30
    });
    
    // 计算属性
    const fullName = ***puted(() => {
         
         
      return `${
           
           user.name} Doe`;
    });
    
    // 监听单个值
    watch(count, (newValue, oldValue) => {
         
         
      console.log(`Count changed from ${
           
           oldValue} to ${
           
           newValue}`);
    });
    
    // 自动追踪依赖的监听
    watchEffect(() => {
         
         
      console.log(`User name is: ${
           
           user.name}`);
    });
    

    Vue 2 与 Vue 3 响应式系统的主要区别

    特性 Vue 2 Vue 3
    核心实现 Object.defineProperty Proxy
    数组响应式 重写数组方法 原生支持
    检测属性添加/删除 不支持,需使用Vue.set/Vue.delete 原生支持
    检测数组索引/长度变化 不支持 部分支持
    嵌套对象响应式 递归遍历到底 按需递归(懒代理)
    TypeScript支持 有限 原生支持
    性能 较大对象初始化较慢 更高效,特别是大型对象
    响应式API 无专用API,通过Vue实例实现 提供ref、reactive等组合式API

2. Vue 组件通信

  • 父组件向子组件传递数据

    • Props传递:静态props和动态props(v-bind:prop)
    • Props类型校验:String、Number、Boolean、Array、Object、Function等
    • Props默认值和必填项设置
    • 单向数据流原则:子组件不应该修改父组件传递的props

    代码示例:父组件向子组件传递数据

    <!-- Parent***ponent.vue -->
    <template>
      <div class="parent">
        <h2>Parent ***ponent</h2>
        <!-- 静态props -->
        <child-***ponent title="Static Title" />
        
        <!-- 动态props -->
        <child-***ponent 
          :message="parentMessage" 
          :user-data="userInfo" 
          :is-active="is***ponentActive" 
        />
        
        <button @click="updateMessage">Update Message</button>
      </div>
    </template>
    
    <script>
    import Child***ponent from './Child***ponent.vue';
    
    export default {
           
           
      ***ponents: {
           
            Child***ponent },
      data() {
           
           
        return {
           
           
          parentMessage: 'Hello from parent',
          userInfo: {
           
           
            name: 'John',
            age: 30
          },
          is***ponentActive: true
        };
      },
      methods: {
           
           
        updateMessage() {
           
           
          this.parentMessage = 'Updated message from parent';
          this.is***ponentActive = !this.is***ponentActive;
        }
      }
    };
    </script>
    
    <!-- Child***ponent.vue -->
    <template>
      <div class="child">
        <h3>{
        
        { title || 'Default Title' }}</h3>
        <p v-if="message">{
        
        { message }}</p>
        <p v-if="userData">User: {
        
        { userData.name }}, Age: {
        
        { userData.age }}</p>
        <p>Status: {
        
        { isActive ? 'Active' : 'Inactive' }}</p>
      </div>
    </template>
    
    <script>
    export default {
           
           
      name: 'Child***ponent',
      props: {
           
           
        // 基础类型检查
        title: String,
        
        // 带默认值的props
        message: {
           
           
          type: String,
          default: 'Default message'
        },
        
        // 复杂类型的props
        userData: {
           
           
          type: Object,
          // 对象或数组默认值必须从一个工厂函数获取
          default: () => ({
           
           }),
          required: false
        },
        
        // 布尔类型props
        isActive: {
           
           
          type: Boolean,
          default: false
        },
        
        // 自定义验证函数
        items: {
           
           
          type: Array,
          validator: (value) => {
           
           
            // 这个值必须匹配下列字符串中的一个
            return value.length > 0;
          },
          default: () => []
        }
      }
    };
    </script>
    
  • 子组件向父组件传递数据

    • 自定义事件:子组件通过$emit('eventName', data)触发事件
    • 父组件通过v-on:eventName="handleEvent"监听事件
    • 事件修饰符在组件上的应用
    • .native修饰符的使用与注意事项

    代码示例:子组件向父组件传递数据

    <!-- Parent***ponent.vue -->
    <template>
      <div class="parent">
        <h2>Parent ***ponent</h2>
        <p>Child message: {
        
        { childMessage }}</p>
        <p>Counter: {
        
        { counter }}</p>
        
        <!-- 监听子组件事件 -->
        <child-***ponent 
          @message-sent="handleMessage" 
          @increment="handleIncrement" 
          @decrement="handleDecrement"
        />
        
        <!-- 带参数的事件处理 -->
        <child-***ponent 
          @update-count="(value) => { counter += value }"
        />
      </div>
    </template>
    
    <script>
    import Child***ponent from './Child***ponent.vue';
    
    export default {
           
           
      ***ponents: {
           
            Child***ponent },
      data() {
           
           
        return {
           
           
          childMessage: '',
          counter: 0
        };
      },
      methods: {
           
           
        handleMessage(message) {
           
           
          this.childMessage = message;
        },
        handleIncrement() {
           
           
          this.counter++;
        },
        handleDecrement() {
           
           
          this.counter--;
        }
      }
    };
    </script>
    
    <!-- Child***ponent.vue -->
    <template>
      <div class="child">
        <h3>Child ***ponent</h3>
        
        <!-- 基本事件触发 -->
        <button @click="sendMessage">Send Message</button>
        
        <!-- 带参数的事件触发 -->
        <button @click="incrementParentCounter">+1</button>
        <button @click="decrementParentCounter">-1</button>
        
        <!-- 带动态参数的事件触发 -->
        <button @click="updateCountBy(5)">+5 to Parent</button>
        <button @click="updateCountBy(-3)">-3 to Parent</button>
        
        <!-- 使用表单输入触发事件 -->
        <input 
          type="text" 
          v-model="inputValue" 
          @input="onInputChange"
          placeholder="Type something..."
        >
      </div>
    </template>
    
    <script>
    export default {
           
           
      name: 'Child***ponent',
      data() {
           
           
        return {
           
           
          inputValue: ''
        };
      },
      methods: {
           
           
        sendMessage() {
           
           
          // 触发自定义事件,可携带数据
          this.$emit('message-sent', 'Hello from child ***ponent!');
        },
        
        incrementParentCounter() {
           
           
          this.$emit('increment');
        },
        
        decrementParentCounter() {
           
           
          this.$emit('decrement');
        },
        
        updateCountBy(value) {
           
           
          this.$emit('update-count', value);
        },
        
        onInputChange() {
           
           
          this.$emit('input-change', this.inputValue);
        }
      },
      // Vue 3中可以显式声明组件发出的事件
      emits: ['message-sent', 'increment', 'decrement', 'update-count', 'input-change']
    };
    </script>
    
  • 兄弟组件间通信

    • EventBus:创建全局事件总线 Vue.prototype.$bus = new Vue()
    • 通过 e m i t 发送事件, emit发送事件, emit发送事件,on监听事件
    • 使用Vuex/Pinia进行状态共享
    • 兄弟组件通信的最佳实践

    代码示例:兄弟组件间通信

    1. 使用EventBus进行兄弟组件通信

    // 在main.js中初始化EventBus
    import Vue from 'vue';
    
    // 方法1: 全局注册EventBus
    Vue.prototype.$bus = new Vue();
    
    // 方法2: 创建独立的EventBus模块
    // event-bus.js
    export const bus = new Vue();
    
    // ***ponentA.vue (发送方组件)
    <template>
      <div class="***ponent-a">
        <h3>***ponent A</h3>
        <button @click="sendMessage">Send Message to B</button>
      </div>
    </template>
    
    <script>
    // 如果使用独立的EventBus模块
    import {
         
          bus } from './event-bus';
    
    export default {
         
         
      methods: {
         
         
        sendMessage() {
         
         
          // 方法1: 使用全局EventBus
          this.$bus.$emit('message-from-a', 'Hello from ***ponent A!');
          
          // 方法2: 使用独立EventBus模块
          // bus.$emit('message-from-a', 'Hello from ***ponent A!');
        }
      }
    };
    </script>
    
    // ***ponentB.vue (接收方组件)
    <template>
      <div class="***ponent-b">
        <h3>***ponent B</h3>
        <p>Message from A: {
         
         {
         
          messageFromA }}</p>
      </div>
    </template>
    
    <script>
    // 如果使用独立的EventBus模块
    import {
         
          bus } from './event-bus';
    
    export default {
         
         
      data() {
         
         
        return {
         
         
          messageFromA: ''
        };
      },
      mounted() {
         
         
        // 方法1: 使用全局EventBus
        this.$bus.$on('message-from-a', (message) => {
         
         
          this.messageFromA = message;
        });
        
        // 方法2: 使用独立EventBus模块
        // bus.$on('message-from-a', (message) => {
         
         
        //   this.messageFromA = message;
        // });
      },
      beforeDestroy() {
         
         
        // 组件销毁前移除事件监听,避免内存泄漏
        this.$bus.$off('message-from-a');
        // 或 bus.$off('message-from-a');
      }
    };
    </script>
    

    2. 使用Vuex进行组件通信

    // store.js
    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
         
         
      state: {
         
         
        sharedData: '',
        counter: 0
      },
      mutations: {
         
         
        setSharedData(state, data) {
         
         
          state.sharedData = data;
        },
        incrementCounter(state) {
         
         
          state.counter++;
        },
        decrementCounter(state) {
         
         
          state.counter--;
        }
      },
      actions: {
         
         
        setSharedDataAction({
          
           ***mit }, data) {
         
         
          // 可以在这里处理异步操作
          ***mit('setSharedData', data);
        }
      },
      getters: {
         
         
        getSharedData: state => state.sharedData,
        getCounter: state => state.counter
      }
    });
    
    // 在main.js中注册store
    import store from './store';
    
    new Vue({
         
         
      store,
      // ...其他配置
    }).$mount('#app');
    
    // Sender***ponent.vue
    <template>
      <div class="sender">
        <h3>Sender ***ponent</h3>
        <input v-model="message" placeholder="Type a message">
        <button @click="updateSharedData">Update Shared Data</button>
        <button @click="increment">Increment Counter</button>
      </div>
    </template>
    
    <script>
    export default {
         
         
      data() {
         
         
        return {
         
         
          message: ''
        };
      },
      methods: {
         
         
        updateSharedData() {
         
         
          // 直接提交mutation
          // this.$store.***mit('setSharedData', this.message);
          
          // 或通过dispatch action(适合处理异步操作)
          this.$store.dispatch('setSharedDataAction', this.message);
        },
        increment() {
         
         
          this.$store.***mit('incrementCounter');
        }
      }
    };
    </script>
    
    // Receiver***ponent.vue
    <template>
      <div class="receiver">
        <h3>Receiver ***ponent</h3>
        <p>Shared Data: {
         
         {
         
          sharedData }}</p>
        <p>Counter: {
         
         {
         
          counter }}</p>
        <button @click="decrement">Decrement Counter</button>
      </div>
    </template>
    
    <script>
    export default {
         
         
      ***puted: {
         
         
        // 方法1: 直接从store获取
        // sharedData() {
         
         
        //   return this.$store.state.sharedData;
        // },
        // counter() {
         
         
        //   return this.$store.state.counter;
        // }
        
        // 方法2: 使用mapState辅助函数
        // ...Vuex.mapState(['sharedData', 'counter'])
        
        // 方法3: 使用mapGetters辅助函数
        ...Vuex.mapGetters(['getSharedData', 'getCounter']),
        sharedData() {
         
         
          return this.getSharedData;
        },
        counter() {
         
         
          return this.getCounter;
        }
      },
      methods: 
转载请说明出处内容投诉
CSS教程网 » Vue 项目开发必备知识点

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买