Vue 基础二(进阶使用)

一、Vue的响应式系统

(一)Vue 响应式的原理

Vue 的核心特性之一是响应式数据绑定系统。它允许我们轻松地将数据与视图进行绑定,当数据发生变化时,视图会自动更新。Vue 内部通过 Object.definePropertyProxy 来实现这一特性。

  1. Object.defineProperty

    • 在 Vue 2.x 中,Vue 使用 Object.defineProperty 来劫持对象的属性。

    • 当我们访问或修改被 Object.defineProperty 定义的属性时,Vue 会触发相应的 getter 和 setter 方法。

    • Getter 用于读取属性值并追踪依赖,Setter 用于设置属性值并通知视图更新。

  2. Proxy

    • 在 Vue 3.x 中,Vue 使用 Proxy 来实现响应式系统。

    • Proxy 提供了更强大和灵活的拦截机制,可以拦截对象的所有操作,包括属性的读取、设置、删除等。

    • Object.defineProperty 相比,Proxy 能够更高效地实现深度响应式。

(二)响应式 API

Vue 提供了一系列响应式相关的 API,用于手动创建响应式对象或追踪数据。

  1. ref :用于创建一个响应式的引用,返回一个包含值的 ref 对象。

JavaScript复制

import { ref } from 'vue';

const count = ref(0);
console.log(count.value); // 0
  1. reactive:用于将一个普通对象转换为响应式对象。

JavaScript复制

import { reactive } from 'vue';

const state = reactive({
  count: 0
});
console.log(state.count); // 0
  1. computed:用于创建一个计算属性,基于响应式依赖,自动追踪依赖并缓存计算结果。

JavaScript复制

import { ref, computed } from 'vue';

const firstName = ref('John');
const lastName = ref('Doe');

const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`;
});
console.log(fullName.value); // John Doe
  1. watch:用于监听响应式数据的变化,并执行回调函数。

JavaScript复制

import { ref, watch } from 'vue';

const count = ref(0);

watch(count, (newVal, oldVal) => {
  console.log(`count 变化了:从 ${oldVal} 变为 ${newVal}`);
});

二、Vue 生命周期

Vue 组件有一个完整的生命周期,从创建到销毁,会依次调用一系列的生命周期钩子函数。以下是 Vue 生命周期的主要钩子函数:

  1. beforeCreate

    • 在实例初始化之后,数据观测和事件配置之前被调用。

    • 此时,datamethods 等属性尚未初始化。

  2. created

    • 在实例创建完成后被调用。

    • 此时,datamethods 等属性已经初始化完毕,可以访问和操作。

  3. beforeMount

    • 在挂载开始之前被调用。

    • 此时,模板已经编译完成,但尚未挂载到 DOM 上。

  4. mounted

    • 在实例挂载完成后被调用。

    • 此时,DOM 已经渲染完成,可以进行 DOM 操作。

  5. beforeUpdate

    • 在数据更新之前被调用。

    • 此时,数据已经更新,但 DOM 尚未更新。

  6. updated

    • 在数据更新完成并重新渲染 DOM 后被调用。

    • 此时,可以重新操作 DOM。

  7. beforeUnmount

    • 在实例销毁之前被调用。

    • 可以在此清理资源,如定时器、事件监听器等。

  8. unmounted

    • 在实例销毁后被调用。

    • 此时,Vue 实例已经完全销毁,无法再进行操作。

三、Vue 的组件

(一)组件的基础知识

  1. 组件的注册

    • 全局注册 :使用 Vue.component 注册的组件可以在全局范围内使用。

JavaScript复制

Vue.component('my-component', {
  template: '<div>This is a global component</div>'
});
  • 局部注册:在单个 Vue 实例或组件中注册的组件。

JavaScript复制

const AppComponent = {
  template: '<div>This is a local component</div>'
};

const app = new Vue({
  components: {
    'my-component': AppComponent
  }
});
  1. 组件的通信

    • 父组件向子组件传递数据 :通过 props

vue复制

<!-- ParentComponent.vue -->
<template>
  <div>
    <child-component :message="parentMessage"></child-component>
  </div>
</template>

<script>
export default {
  data() {
    return {
      parentMessage: 'Hello from parent'
    };
  }
};
</script>

vue复制

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

<script>
export default {
  props: {
    message: {
      type: String,
      required: true
    }
  }
};
</script>
  • 子组件向父组件传递事件 :通过 $emit

vue复制

<!-- ChildComponent.vue -->
<template>
  <div @click="$emit('child-event', 'Hello from child')">Click me</div>
</template>

<script>
export default {
  methods: {
    handleClick() {
      this.$emit('child-event', 'Hello from child');
    }
  }
};
</script>

vue复制

<!-- ParentComponent.vue -->
<template>
  <div>
    <child-component @child-event="handleChildEvent"></child-component>
  </div>
</template>

<script>
export default {
  methods: {
    handleChildEvent(message) {
      console.log(message); // Hello from child
    }
  }
};
</script>
  1. 动态组件 :使用 <component> 标签和 is 属性动态切换组件。

vue复制

<template>
  <div>
    <button @click="currentComponent = 'ComponentA'">Show A</button>
    <button @click="currentComponent = 'ComponentB'">Show B</button>
    <component :is="currentComponent"></component>
  </div>
</template>

<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';

export default {
  components: {
    ComponentA,
    ComponentB
  },
  data() {
    return {
      currentComponent: 'ComponentA'
    };
  }
};
</script>

(二)组件的高级特性

  1. 插槽(Slots):插槽允许父组件向子组件传递自定义内容。

    • 默认插槽

vue复制

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

vue复制

<!-- ParentComponent.vue -->
<template>
  <div>
    <child-component>
      <p>This is inserted into the slot</p>
    </child-component>
  </div>
</template>
  • 具名插槽

vue复制

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot name="header"></slot>
    <slot name="content"></slot>
  </div>
</template>

vue复制

<!-- ParentComponent.vue -->
<template>
  <div>
    <child-component>
      <template v-slot:header>
        <h2>Header</h2>
      </template>
      <template v-slot:content>
        <p>Content</p>
      </template>
    </child-component>
  </div>
</template>
  • 作用域插槽

vue复制

<!-- ChildComponent.vue -->
<template>
  <div>
    <slot :user="user"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: { name: 'John' }
    };
  }
};
</script>

vue复制

<!-- ParentComponent.vue -->
<template>
  <div>
    <child-component v-slot:default="slotProps">
      <p>{{ slotProps.user.name }}</p>
    </child-component>
  </div>
</template>
  1. 动态组件与缓存 :使用 keep-alive 缓存动态组件,避免重复渲染。

vue复制

<template>
  <div>
    <keep-alive>
      <component :is="currentComponent"></component>
    </keep-alive>
  </div>
</template>
  1. 异步组件:允许组件以异步的方式加载,提高首屏加载速度。

JavaScript复制

const AsyncComponent = () => ({
  component: import('./AsyncComponent.vue')
});

四、Vue 的状态管理

(一)Vuex 简介

Vuex 是 Vue 官方的状态管理库,用于集中管理Vue 应用中的状态。

  1. 安装 Vuex

bash复制

npm install vuex --save
  1. 基本使用

JavaScript复制

// store.js
import Vuex from 'vuex';
Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment');
      }, 1000);
    }
  },
  getters: {
    doubleCount: state => state.count * 2
  }
});

export default store;
  1. 在组件中使用 Vuex

vue复制

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
    <button @click="incrementAsync">Increment Async</button>
  </div>
</template>

<script>
export default {
  computed: {
    count() {
      return this.$store.state.count;
    }
  },
  methods: {
    increment() {
      this.$store.commit('increment');
    },
    incrementAsync() {
      this.$store.dispatch('incrementAsync');
    }
  }
};
</script>

(二)Vuex 的核心概念

  1. State:存储应用的状态数据。

JavaScript复制

state: {
  count: 0
}
  1. Getter:类似于计算属性,用于从 state 中派生出一些状态。

JavaScript复制

getters: {
  doubleCount: state => state.count * 2
}
  1. Mutations:用于改变 state 的唯一方式,必须是同步操作。

JavaScript复制

mutations: {
  increment(state) {
    state.count++;
  }
}
  1. Actions:用于提交 mutations,可以包含异步操作。

JavaScript复制

actions: {
  incrementAsync({ commit }) {
    setTimeout(() => {
      commit('increment');
    }, 1000);
  }
}

五、Vue Router

Vue Router 是 Vue 官方的路由管理器,用于实现单页应用中的页面跳转。

(一)安装 Vue Router

bash复制

npm install vue-router --save

(二)基本使用

JavaScript复制

// main.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import Home from './components/Home.vue';
import About from './components/About.vue';

Vue.use(VueRouter);

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

const router = new VueRouter({
  routes
});

new Vue({
  router,
  render: h => h(App)
}).$mount('#app');

(三)路由导航

vue复制

<!-- App.vue -->
<template>
  <div>
    <nav>
      <router-link to="/">Home</router-link>
      <router-link to="/about">About</router-link>
    </nav>
    <router-view></router-view>
  </div>
</template>

(四)路由参数

JavaScript复制

// routes.js
{ path: '/user/:id', component: User }

// User.vue
export default {
  computed: {
    userId() {
      return this.$route.params.id;
    }
  }
};

(五)路由守卫

JavaScript复制

// 全局前置守卫
router.beforeEach((to, from, next) => {
  // 在渲染该组件的对应路由之前调用
  console.log('beforeEach');
  next();
});

// 全局后置守卫
router.afterEach((to, from) => {
  console.log('afterEach');
});

// 路由独享守卫
const Home = {
  template: '<div>Home</div>',
  beforeEnter(to, from, next) {
    console.log('beforeEnter Home');
    next();
  }
};

六、Vue 的 Mixins

Mixins 是一种分发 Vue 组件中可复用功能的灵活方式。它允许我们将多个组件共用的逻辑提取到一个对象中,然后在多个组件中使用。

JavaScript复制

// mixin.js
export const myMixin = {
  data() {
    return {
      message: 'Hello from mixin'
    };
  },
  created() {
    console.log('Mixin created');
  },
  methods: {
    myMethod() {
      console.log('Mixin method');
    }
  }
};

在组件中使用 Mixin:

JavaScript复制

import { myMixin } from './mixin.js';

export default {
  mixins: [myMixin],
  created() {
    console.log('Component created');
  }
};

七、Vue 的插件

Vue 的插件可以扩展 Vue 的功能,通常用于全局功能的添加,如添加全局方法或属性、注册组件等。

JavaScript复制

// myPlugin.js
export default {
  install(Vue, options) {
    // 添加全局方法
    Vue.myGlobalMethod = (message) => {
      console.log(message);
    };

    // 添加实例方法
    Vue.prototype.$myMethod = (message) => {
      console.log(message);
    };

    // 注册全局组件
    Vue.component('my-component', {
      template: '<div>This is a global component</div>'
    });
  }
};

在项目中安装插件:

JavaScript复制

import Vue from 'vue';
import MyPlugin from './myPlugin.js';

Vue.use(MyPlugin);

八、Vue 的过渡与动画

Vue 提供了过渡和动画的支持,可以轻松地为 DOM 变化添加效果。

(一)使用 transition 进行过渡

vue复制

<template>
  <div>
    <button @click="show = !show">Toggle</button>
    <transition name="fade">
      <p v-if="show">Fade Transition</p>
    </transition>
  </div>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s;
}

.fade-enter,
.fade-leave-to {
  opacity: 0;
}
</style>

(二)使用 animate.css 实现动画

vue复制

<template>
  <div>
    <button @click="show = !show">Toggle</button>
    <transition name="bounce"
      enter-active-class="animate__animated animate__bounceIn"
      leave-active-class="animate__animated animate__bounceOut">
      <p v-if="show">Bounce Animation</p>
    </transition>
  </div>
</template>

九、Vue 的测试

(一)单元测试

Vue 提供了丰富的测试工具和框架,如 Jest 和 Vue Test Utils。

安装:

bash复制

npm install --save-dev jest @vue/test-utils vue-jest

示例:

JavaScript复制

// MyComponent.spec.js
import { shallowMount } from '@vue/test-utils';
import MyComponent from '@/components/MyComponent.vue';

describe('MyComponent.vue', () => {
  it('renders a message', () => {
    const wrapper = shallowMount(MyComponent);
    expect(wrapper.text()).toContain('Hello World');
  });
});

(二)端到端测试

可以使用 Cypress 或 Nightwatch 等工具进行端到端测试。

安装 Cypress:

bash复制

npm install cypress --save-dev

编写测试:

JavaScript复制

describe('MyApp', () => {
  it('should display the title', () => {
    cy.visit('/');
    cy.contains('h1', 'Welcome to Vue.js');
  });
});

十、Vue 的优化

(一)代码分割

通过代码分割,可以将大文件拆分成多个小文件,按需加载,提高首屏加载速度。

JavaScript复制

// 使用动态导入
const MyComponent = () => import('./MyComponent.vue');

(二)性能优化

  1. 避免不必要的渲染 :使用 v-oncev-memo

  2. 使用 keep-alive 缓存组件:减少组件的重复渲染。

  3. 优化数据绑定 :减少不必要的 watchcomputed

(三)SEO 优化

Vue 应用可以通过以下方式优化 SEO:

  1. 服务器端渲染(SSR):使用 Vue Server Renderer 渲染页面内容。

  2. 预渲染 :使用 prerender-spa-plugin 预渲染页面。

总结

Vue 是一个功能强大且灵活的前端框架,通过进阶学习,可以更好地掌握其核心特性,如响应式系统、生命周期、状态管理、路由、动画等。同时,了解如何优化 Vue 应用,进行单元测试和端到端测试,对于构建高效、可维护的现代 Web 应用至关重要。希望本文能够帮助你更好地理解和应用 Vue 的进阶知识。

相关推荐
强强学习1 小时前
HTML5 起步
前端·html·html5
念九_ysl3 小时前
前端循环全解析:JS/ES/TS 循环写法与实战示例
前端·javascript·typescript
anyup_前端梦工厂5 小时前
了解几个 HTML 标签属性,实现优化页面加载性能
前端·html
前端御书房5 小时前
前端PDF转图片技术调研实战指南:从踩坑到高可用方案的深度解析
前端·javascript
2301_789169545 小时前
angular中使用animation.css实现翻转展示卡片正反两面效果
前端·css·angular.js
风口上的猪20156 小时前
thingboard告警信息格式美化
java·服务器·前端
程序员黄同学6 小时前
请谈谈 Vue 中的响应式原理,如何实现?
前端·javascript·vue.js
爱编程的小庄7 小时前
web网络安全:SQL 注入攻击
前端·sql·web安全
宁波阿成8 小时前
vue3里组件的v-model:value与v-model的区别
前端·javascript·vue.js
柯腾啊8 小时前
VSCode 中使用 Snippets 设置常用代码块
开发语言·前端·javascript·ide·vscode·编辑器·代码片段