Vue的初步学习
一、什么是 Vue.js?
Vue.js 是一个渐进式 JavaScript 框架,用于构建用户界面。 它专注于 View 层,易于上手,并且可以与其他库或现有项目更紧密地集成。
主要特性:
渐进式: 你可以逐渐地将 Vue 集成到你的项目中,而不必一次性重写整个应用。
组件化: Vue 基于组件构建,组件是可复用的、独立的 UI 单元。
数据驱动: Vue 的数据绑定系统使得数据变化时,视图会自动更新 (响应式)。
轻量级: Vue 的核心库很小,易于学习和使用。
虚拟 DOM: Vue 使用虚拟 DOM 来进行高效的 DOM 操作。
模板语法: 方便的声明式模板系统。
易于集成: 可以与现有项目无缝集成。
活跃的社区和生态系统: 丰富的文档、教程以及各种用于状态管理、路由、UI 库等功能的插件。
二、Vue.js 的基础知识
1.引入 Vue.js:
(1)通过 CDN: 在 HTML 文件中引入 Vue.js 的 CDN 链接。
<script src="https://unpkg.com/vue@next"></script> <!-- 最新版本 -->
<!-- 或者 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.global.js"></script> <!-- Vue.js 2.x -->
(2)通过 npm 或 yarn: 在你的项目中安装 Vue.js。
npm install vue@next # 或者 npm install vue@2 (vue2)
# 或者
yarn add vue@next # 或者 yarn add vue@2 (vue2)
然后在你的 JavaScript 文件中引入:
import { createApp } from 'vue'; // Vue 3
// 或者
const Vue = require('vue'); // Vue 2 (CommonJS)
2.创建 Vue 实例 (根实例 / main.js):
创建 Vue 实例是开始使用 Vue 的关键。
Vue 3:
import { createApp } from 'vue';const app = createApp({data() { // 用于存储组件的数据return {message: 'Hello Vue!'};},methods: { // 用于定义组件的方法greet() {alert(this.message);}},template: `<div>{{ message }}<button @click="greet">点击我</button></div>`
});app.mount('#app'); // 将实例挂载到 DOM 元素上 (#app 是一个 HTML 元素的 ID)
Vue 2:
new Vue({el: '#app', // (Vue 2) 挂载点,等同于 Vue 3 的 app.mount('#app')data: {message: 'Hello Vue!'},methods: {greet() {alert(this.message);}},template: `<div>{{ message }}<button @click="greet">点击我</button></div>`
});
data()
: (Vue 3) 一个函数,用于返回一个包含组件数据的对象。 (Vue 2 直接是对象)methods
: 一个包含组件方法的对象。template
: 组件的 HTML 模板。 支持模板字符串,JSX (结合 render 函数),或者 .vue 文件 (Single File Components)。el
: (Vue 2) 挂载点,值为 CSS 选择器 (例如#app
)。 Vue 3 使用app.mount('#app')
,更加灵活。mount('#app')
: (Vue 3) 将 Vue 实例挂载到 DOM 元素上。 在Vue 2是el
。
3.模板语法 (Template Syntax):
Vue 使用基于 HTML 的模板语法,方便地声明式地构建你的 UI。
Mustache 语法 (双大括号): 用于插值 (显示数据)。
<h1>{{ message }}</h1>
Directive (指令): 以 v-
开头的特殊 HTML 属性,用于将 DOM 属性绑定到 Vue 实例的数据。
v-bind
: 用于动态地绑定 HTML 属性,例如 class
, style
, 以及其他属性。 简写为 :
。
<img v-bind:src="imageSrc">
<div :class="{ active: isActive }"></div> <!-- 简写 -->
<div :style="{ color: textColor, fontSize: fontSize + 'px' }"></div>
v-on
: 用于监听 DOM 事件。 简写为 @
。
<button v-on:click="handleClick">点击</button>
<button @click="handleClick">点击 (简写)</button>
v-model
: 用于创建双向数据绑定,通常用于表单输入元素 (例如 <input>,
<textarea>,
<select>
)。
<input type="text" v-model="message">
<p>你输入的内容是:{{ message }}</p>
v-if
, v-else
, v-else-if
: 条件渲染。
<p v-if="seen">现在看到了我</p>
<p v-else>现在没看到我</p>
v-show
: 根据条件显示或隐藏元素 (通过切换 display
属性),性能消耗较小,适用于频繁切换显示状态。
<p v-show="seen">显示或隐藏</p>
v-for
: 列表渲染。
<ul><li v-for="(item, index) in items" :key="index">{{ index }} - {{ item.text }}</li>
</ul>
key
属性对于列表渲染的性能优化非常重要。
4.数据驱动 (响应式系统):
当数据变化时,Vue 会自动更新视图。
Vue使用 Proxy
(Vue 3) 或 Object.defineProperty()
(Vue 2) 来监听数据的变化(追踪依赖)。 只有在 data
中声明的属性是响应式的。
声明式渲染: 通过模板使用数据来定义页面内容。
响应式更新: 当数据发生变化时,Vue 会自动更新与其相关的视图。
5.计算属性 (Computed Properties):
用于根据现有的数据计算派生值。 计算属性是基于它们的依赖进行缓存的,只有当依赖的值发生变化时,计算属性才会重新计算。
const app = createApp({data() {return {firstName: 'John',lastName: 'Doe'};},computed: {fullName() {return this.firstName + ' ' + this.lastName;}},template: `<p>全名:{{ fullName }}</p>`
});
6.侦听器 (Watchers):
侦听器用于观察数据的变化,并执行相应的操作。 当需要在数据变化后执行异步操作或监听特定数据变化时,可以使用侦听器。
const app = createApp({data() {return {firstName: 'John',lastName: 'Doe',fullName: '' // 使用一个空字符串来存储更新后的值};},watch: {firstName(newValue, oldValue) {this.updateFullName();},lastName(newValue, oldValue) {this.updateFullName();}},methods: {updateFullName() {this.fullName = this.firstName + ' ' + this.lastName;}},template: `<p>全名:{{ fullName }}</p><input type="text" v-model="firstName"><input type="text" v-model="lastName">`
});
7.组件 (Components):
组件是 Vue 应用的基本构建块,是可复用的、独立的 UI 单元。
全局注册组件: 使用 Vue.component()
(Vue 2) 或 app.component()
(Vue 3)。 全局组件在任何 Vue 实例中都可用。 一般不推荐全局注册,更推荐局部注册,方便管理,减少命名冲突。
// Vue 2 全局注册
Vue.component('my-component', {template: '<div>这是一个全局组件</div>'
});// Vue 3 全局注册
app.component('my-component', {template: '<div>这是一个全局组件</div>'
});
局部注册组件: 在 components
选项中注册组件。 局部组件只能在其父组件中使用。 推荐使用局部注册。
const MyComponent = {template: '<div>这是一个局部组件</div>'
};const app = createApp({components: {'my-component': MyComponent // 局部组件注册},// ...
});
组件之间的通信:
父组件向子组件传递数据 (Props): 通过在子组件的 props
选项中声明属性,父组件通过属性向子组件传递数据。
// 子组件
const ChildComponent = {props: ['message', 'name'], // 声明接收的 propstemplate: '<div>{{ message }},你好,{{ name }}!</div>'
};// 父组件
const app = createApp({components: {'child-component': ChildComponent},data() {return {parentMessage: '来自父组件的消息',myName: 'Parent'};},template: '<child-component :message="parentMessage" :name="myName"></child-component>'
});
子组件向父组件传递事件 (自定义事件): 子组件通过 emit
方法触发自定义事件,父组件监听这些事件。
// 子组件
const ChildComponent = {template: '<button @click="sendEvent">触发事件</button>',methods: {sendEvent() {this.$emit('my-event', 'Hello from child'); // 触发 my-event 事件,并携带数据}}
};// 父组件
const app = createApp({components: {'child-component': ChildComponent},methods: {handleEvent(payload) {console.log('Received event from child:', payload);}},template: '<child-component @my-event="handleEvent"></child-component>'
});
通过 $refs
(不推荐): 父组件可以通过 $refs.(子组件的ref属性值)
访问子组件实例(不推荐,除非特殊原因)。
<child-component ref="myChild"></child-component>
<button @click="getChildData">获取子组件数据</button>
methods: {getChildData() {console.log(this.$refs.myChild.someData); // 访问子组件的数据 (不推荐)}
}
8.生命周期钩子 (Lifecycle Hooks):
生命周期钩子允许你在 Vue 组件的不同阶段插入自定义逻辑。
Vue 3 (组合式 API,
setup
钩子):onBeforeMount
: 在挂载 DOM 之前调用。onMounted
: 在挂载 DOM 之后调用 (最常用)。onBeforeUpdate
: 在数据变化,DOM 更新之前调用。onUpdated
: 在 DOM 更新之后调用。onBeforeUnmount
: 在组件卸载之前调用。onUnmounted
: 在组件卸载之后调用。onErrorCaptured
: 当捕获到一个来自后代组件的错误时被调用。onRenderTracked
: 调试组件重渲染的依赖时调用。onRenderTriggered
: 调试组件重渲染的原因时调用。
import { ref, onMounted } from 'vue';const app = {setup() { //setup 是最关键的, 组合式API开始const message = ref('Hello!');onMounted(() => {console.log('组件已挂载');});//...其他}
}
app.mount('#app');
Vue 2 (选项式 API):
beforeCreate
: 在实例被创建之前调用。created
: 在实例被创建之后调用 (数据已初始化,但 DOM 还未挂载)。beforeMount
: 在挂载 DOM 之前调用。mounted
: 在挂载 DOM 之后调用 (最常用)。beforeUpdate
: 在数据变化,DOM 更新之前调用。updated
: 在 DOM 更新之后调用。beforeDestroy
: 在实例被销毁之前调用。destroyed
: 在实例被销毁之后调用。
new Vue({data() {return {message: 'Hello'}},mounted() {console.log('组件已挂载');},template: ...
});
9.单文件组件 (Single File Components, .vue 文件):
.vue 文件是 Vue 推荐的开发方式。 在一个文件中包含 HTML 模板、JavaScript 逻辑和 CSS 样式。
<template><div><h1>{{ message }}</h1><button @click="handleClick">点击</button></div>
</template><script>
export default {data() {return {message: 'Hello from Vue!'};},methods: {handleClick() {alert(this.message);}}
};
</script><style scoped> // scoped 属性使得样式只对当前组件生效
h1 {color: blue;
}
</style>
<template>
: 组件的 HTML 模板。<script>
: 组件的 JavaScript 逻辑 (数据,方法,生命周期钩子等)。<style>
: 组件的 CSS 样式。
三、Vue 3 的主要变化 (和 Vue 2 的区别)
Composition API (组合式 API): Vue 3 引入了 Composition API,这是一种编写组件逻辑的新方式,可以更好地组织和重用组件中的逻辑。它使用
setup()
函数作为组件的入口点。 相比于 Options API, 更加灵活。性能提升: 虚拟 DOM 的改进,更快的渲染速度。
更好的 TypeScript 支持: Vue 3 专门为 TypeScript 设计,提供了更好的类型推断和代码提示。
更好的代码树摇动 (Tree-shaking): 更有效地减小打包后的文件大小,减少不必要的代码,提高效率。
createApp()
API: Vue 3 使用createApp()
来创建 Vue 应用实例,而不是直接使用new Vue()
。移除
$children
和$listeners
: 不推荐使用,使用父子组件数据传递和事件传递。更好的自定义渲染 API: 更灵活地自定义 Vue 的渲染行为。
Composition API vs Options API:
特性 | Options API (Vue 2 & 3) | Composition API (Vue 3) |
---|---|---|
组织代码 | 基于选项 (data, methods, etc.) | 在 setup() 函数中组合逻辑 |
代码可读性 | 代码分散,逻辑难以复用 | 逻辑内聚,代码更容易共享和复用 |
代码复用 | mixin、高阶组件 | 自定义 hook |
TypeScript 支持 | 弱,需要手动声明类型 | 更好,自动类型推断 |
逻辑组合 | 困难 | 简单,更易于组合相关状态和方法 |
四、Vue Router (路由)
Vue Router 是 Vue.js 的官方路由库,用于构建单页面应用程序 (SPA)。
1.安装:
npm install vue-router@4 # Vue 3
# 或者
npm install vue-router@3 # Vue 2
2.配置路由:
// Vue 3
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from './views/HomeView.vue'; // 导入组件const routes = [{path: '/',name: 'home',component: HomeView},{path: '/about',name: 'about',component: () => import('./views/AboutView.vue') // 懒加载}
];const router = createRouter({history: createWebHistory(), // 使用 HTML5 history 模式routes
});export default router;
//Vue2
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from './components/Home.vue'Vue.use(VueRouter)const routes = [{path: '/',component: Home},{path: '/about',component: () => import('./components/About.vue')// 懒加载}
]const router = new VueRouter({routes
})export default router
3.在main.js 中使用路由:
// Vue 3
import { createApp } from 'vue';
import router from './router';
import App from './App.vue';const app = createApp(App);
app.use(router); // 使用路由
app.mount('#app');
//Vue 2
import Vue from 'vue'
import App from './App.vue' // 根组件
import router from './router'new Vue({el: '#app',router,render: h => h(App)
})
4.在模板中使用 <router-link>
和 <router-view>
:
<router-link>
: 用于创建导航链接. to
属性指定要跳转的路由地址.
<router-link to="/">首页</router-link>
<router-link to="/about">关于我们</router-link>
<router-view>
: 用于显示当前路由匹配的组件.
<router-view></router-view>
5.动态路由:
在路由中定义带参数的路径routes.js文件
{path: '/user/:id',name: 'user',component: User}
在组件中获取参数:
import { useRoute } from 'vue-router';
const route = useRoute();
const userId = route.params.id;
Vue2 获取路由参数:
this.$route.params.id
6.导航守卫:
用于在路由跳转过程中执行逻辑。
全局前置守卫: 在每次导航之前调用。
router.beforeEach((to, from, next) => {// to: 即将要进入的路由// from: 当前导航正要离开的路由// next(): 必须调用,以 resolve 钩子。// next():进行跳转。next(false):取消导航。 next('/login'):跳转到指定的路由。if (to.meta.requiresAuth && !isAuthenticated) {next('/login'); // 导航到登录页面} else {next(); // 继续导航}
});
路由独享守卫: 定义在单个路由配置中。
const routes = [{path: '/profile',component: Profile,beforeEnter: (to, from, next) => {// 路由独享守卫if (!isAuthenticated) {next('/login');} else {next();}}}
];
组件内守卫: 定义在组件内部。
beforeRouteEnter
: 在进入路由前调用。beforeRouteUpdate
: 在当前路由改变,但是路由组件被复用时调用beforeRouteLeave
: 在离开当前路由前调用。
六、其他重要概念和技术
Props 和 Emit: 组件间的核心通信方法。
Slot (插槽): 允许你创建具有灵活内容的组件。 默认插槽
、具名插槽
、作用域插槽
。
动态组件: 使用 is
属性动态切换组件。 提供灵活的组件渲染方式。
<component :is="currentTabComponent"></component>
异步组件: Vue.defineAsyncComponent()
(Vue 3) 或 懒加载组件技术,可以按需加载组件,提高页面加载速度。
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() =>import('./components/AsyncComponent.vue')
);
指令 (Directives): 自定义指令可以扩展 HTML 。
自定义指令示例: 注册一个名为
v-focus
的指令,当元素在页面显示时自动获取焦点。
// Vue 3
import { createApp } from 'vue';const app = createApp({});app.directive('focus', {mounted(el) {el.focus();}
});app.mount('#app');
// Vue 2
Vue.directive('focus', {inserted: function (el) {el.focus();}
})
在模板中使用
<input type="text" v-focus>
bind
: 只调用一次,当指令第一次绑定到元素上时。inserted
: 当元素插入到 DOM 中时调用。update
: 当绑定的值发生变化时调用。componentUpdated
: 当组件 VNode 以及其子 VNode 全部更新之后调用。unbind
: 只调用一次,当指令从元素上移除时。
Transition (过渡效果): Vue 提供了 transition
组件,用于实现 CSS 过渡和动画效果。
<transition name="fade"><p v-if="show">现在显示</p>
</transition>
name
: 指定过渡的名称。CSS 过渡类名:
v-enter-from
: 过渡开始状态的 CSS 类名。v-enter-active
: 过渡进行中的 CSS 类名。v-enter-to
: 过渡结束状态的 CSS 类名。v-leave-from
: 离开开始状态的 CSS 类名。v-leave-active
: 离开进行中的 CSS 类名。v-leave-to
: 离开结束状态的 CSS 类名。
可以使用 CSS transitions 或者 CSS animations。
Vue CLI / Vite: Vue CLI/Vite 是官方提供的脚手架工具,用于快速创建 Vue.js 项目,提供了开发环境、代码构建、热更新等功能。
Vite
采用“模块预构建”和“按需编译”的方式,比Vue CLI
速度更快。测试: 使用 Jest, Vue Test Utils (VTU), 或者 Cypress 等工具进行 Vue 组件的测试。