Vue.js 是一个用于构建用户界面的渐进式框架。Vue 2 是目前广泛使用的一个版本,它提供了简洁的 API 和强大的功能,使得开发者能够快速创建复杂的单页面应用(SPA)。以下是一个基础教程,帮助你开始使用 Vue 2。
对于简单的项目或学习目的,你可以直接通过 CDN 引入 Vue:
html<!DOCTYPE html>
<html>
<head>
<title>Vue 2 Example</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
</script>
</body>
</html>
对于更复杂的应用,推荐使用 npm 或 yarn 来安装 Vue:
bashnpm install vue@2
# 或者
yarn add vue@2
然后在你的 JavaScript 文件中引入 Vue:
javascriptimport Vue from 'vue';
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
每个 Vue 应用都是从一个 Vue 实例开始的。Vue 实例需要绑定到一个 DOM 元素,并且可以包含数据、方法、生命周期钩子等。
javascriptvar vm = new Vue({
el: '#app', // 绑定元素的选择器
data: { // 数据对象
message: 'Hello Vue!'
},
methods: { // 方法集合
reverseMessage: function () {
this.message = this.message.split('').reverse().join('');
}
}
});
Vue 使用基于 HTML 的模板语法,允许你声明式地将 DOM 绑定至底层 Vue 实例的数据。
{{ }}
进行文本插值。v-html
指令输出原始 HTML 内容。v-bind
指令动态绑定属性。html<div id="app">
<p>{{ message }}</p>
<p v-html="rawHtml"></p>
<a v-bind:href="url">Link</a>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue!',
rawHtml: '<span style="color: red;">This should be red.</span>',
url: 'https://vuejs.org'
}
});
</script>
计算属性是基于其他数据属性计算得出的属性。
html<div id="app">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello'
},
computed: {
reversedMessage: function () {
return this.message.split('').reverse().join('');
}
}
});
</script>
当需要执行异步操作或开销较大的操作时,侦听器非常有用。
javascriptvar vm = new Vue({
el: '#app',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
question: function (newQuestion) {
this.answer = 'Waiting for you to stop typing...';
this.getAnswer();
}
},
methods: {
getAnswer: function () {
// Simulate an async operation
setTimeout(() => {
this.answer = 'Your question is "' + this.question + '"';
}, 1000);
}
}
});
Vue 可以让你动态地添加或移除 CSS 类和内联样式。
html<div id="app">
<div v-bind:class="{ active: isActive, 'text-danger': hasError }">Class Binding</div>
</div>
<script>
new Vue({
el: '#app',
data: {
isActive: true,
hasError: false
}
});
</script>
html<div id="app">
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">Style Binding</div>
</div>
<script>
new Vue({
el: '#app',
data: {
activeColor: 'red',
fontSize: 30
}
});
</script>
使用 v-if
, v-else
, v-show
等指令来实现条件渲染。
html<div id="app">
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
</div>
<script>
new Vue({
el: '#app',
data: {
awesome: true
}
});
</script>
使用 v-for
指令来遍历数组或对象。
html<div id="app">
<ul>
<li v-for="(item, index) in items" :key="index">{{ item.message }}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
});
</script>
Vue 使用 v-model
指令来创建双向数据绑定。
html<div id="app">
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: ''
}
});
</script>
组件是 Vue 中最重要的概念之一。它们可以扩展 HTML 元素,封装可重用的代码。
javascriptVue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
});
var app = new Vue({
el: '#app',
data: {
groceryList: [
{ id: 0, text: 'Vegetables' },
{ id: 1, text: 'Cheese' },
{ id: 2, text: 'Whatever else humans are supposed to eat' }
]
}
});
html<div id="app">
<ol>
<todo-item v-for="item in groceryList" v-bind:todo="item" v-bind:key="item.id"></todo-item>
</ol>
</div>
Vue 提供了 v-on
指令来监听 DOM 事件,并在触发时执行 JavaScript 代码。
html<div id="app">
<button v-on:click="incrementCounter">Click me</button>
<p>The button has been clicked {{ counter }} times.</p>
</div>
<script>
new Vue({
el: '#app',
data: {
counter: 0
},
methods: {
incrementCounter: function () {
this.counter += 1;
}
}
});
</script>
Vue 提供了一些事件修饰符,例如 .stop
, .prevent
, .capture
, .self
等,用于简化常见的事件行为。
html<div id="app">
<div @click="doThis">
<button @click.stop="doThat">Click Me</button>
</div>
</div>
html<form v-on:submit.prevent="onSubmit">
<button type="submit">Submit</button>
</form>
除了内置指令(如 v-model
, v-bind
),Vue 还允许你注册自定义指令。
javascriptVue.directive('focus', {
inserted: function (el) {
el.focus();
}
});
使用:
html<input v-focus>
javascriptnew Vue({
el: '#app',
directives: {
focus: {
inserted: function (el) {
el.focus();
}
}
}
});
插槽是 Vue 中用于分发内容的机制,允许你在组件中插入任意内容。
html<!-- 子组件 -->
<template>
<div class="child-component">
<slot>Default content</slot>
</div>
</template>
<!-- 父组件 -->
<div id="app">
<child-component>
<p>This is some content passed to the child component.</p>
</child-component>
</div>
html<!-- 子组件 -->
<template>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</template>
<!-- 父组件 -->
<div id="app">
<child-component>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</child-component>
</div>
Vue 支持动态加载和异步加载组件,这对于大型应用尤其有用。
使用 <component>
元素和 is
属性来动态切换组件。
html<div id="app">
<button @click="currentComponent = 'ComponentA'">Load A</button>
<button @click="currentComponent = 'ComponentB'">Load B</button>
<component :is="currentComponent"></component>
</div>
<script>
const ComponentA = { template: '<div>Component A</div>' };
const ComponentB = { template: '<div>Component B</div>' };
new Vue({
el: '#app',
data: {
currentComponent: 'ComponentA'
},
components: {
ComponentA,
ComponentB
}
});
</script>
javascriptVue.component('async-example', function (resolve, reject) {
setTimeout(function () {
resolve({
template: '<div>I am async!</div>'
});
}, 1000);
});
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
bashnpm install vuex@3
javascriptimport Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
increment({ commit }) {
commit('increment');
}
}
});
new Vue({
el: '#app',
store,
computed: {
count() {
return this.$store.state.count;
}
},
methods: {
increment() {
this.$store.dispatch('increment');
}
}
});
Vue Router 是官方路由管理器,与 Vue.js 核心深度集成,让构建单页面应用变得轻而易举。
bashnpm install vue-router@3
javascriptimport Vue from 'vue';
import VueRouter from 'vue-router';
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,
el: '#app'
});
html<div id="app">
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-view></router-view>
</div>
Mixins 是一种灵活的方式来复用 Vue 组件中的代码。
javascriptvar myMixin = {
created: function () {
console.log('Mixin hook called');
},
methods: {
sharedMethod: function () {
console.log('This method is shared');
}
}
};
javascriptvar vm = new Vue({
mixins: [myMixin],
created: function () {
console.log('Component hook called');
}
});
虽然 Vue 2.x 已经移除了内置的过滤器功能,但你可以通过计算属性或方法实现类似的功能。
javascriptnew Vue({
el: '#app',
data: {
price: 1234.56
},
filters: {
currency: function (value) {
if (!value) return '';
return '$' + value.toFixed(2);
}
}
});
使用:
html<div id="app">
<p>{{ price | currency }}</p>
</div>
每个 Vue 实例在创建过程中会经历一系列初始化步骤,例如设置数据观察、编译模板、挂载实例到 DOM 上等。同时,也提供了一系列生命周期钩子,让你可以在特定阶段添加自己的代码。
beforeCreate
: 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。created
: 在实例创建完成后被立即调用。beforeMount
: 在挂载开始之前被调用。mounted
: 在挂载完成后被调用。beforeUpdate
: 数据更新时调用,发生在虚拟 DOM 打补丁之前。updated
: 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。beforeDestroy
: 实例销毁之前调用。destroyed
: 实例销毁后调用。示例:
javascriptnew Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
beforeCreate: function () {
console.log('beforeCreate');
},
created: function () {
console.log('created');
},
mounted: function () {
console.log('mounted');
}
});
Vue 提供了一个内置的 <transition>
组件来实现元素进入或离开时的过渡效果。
html<div id="app">
<button @click="show = !show">Toggle</button>
<transition name="fade">
<p v-if="show">Hello, Vue!</p>
</transition>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: '#app',
data: {
show: true
}
});
</script>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
opacity: 0;
}
</style>
使用 <transition-group>
来为列表项添加动画。
html<div id="app">
<button @click="addItem">Add Item</button>
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item">{{ item }}</li>
</transition-group>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: '#app',
data: {
items: [1, 2, 3],
nextNum: 4
},
methods: {
randomIndex: function () {
return Math.floor(Math.random() * this.items.length)
},
addItem: function () {
this.items.splice(this.randomIndex(), 0, this.nextNum++)
}
}
});
</script>
<style>
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to /* .list-leave-active for <2.1.8 */ {
opacity: 0;
transform: translateY(30px);
}
</style>
Vue 可以通过 v-model
实现对表单元素的双向绑定。除了基本的文本框、复选框等,还可以自定义输入组件。
javascriptVue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
});
new Vue({
el: '#app',
data: {
searchText: ''
}
});
使用:
html<div id="app">
<custom-input v-model="searchText"></custom-input>
<p>{{ searchText }}</p>
</div>
在开发过程中,正确处理错误对于维护应用的稳定性至关重要。Vue 提供了全局和局部两种方式来捕获错误。
javascriptVue.config.errorHandler = function (err, vm, info) {
console.error(`Error: ${err.toString()}\nInfo: ${info}`);
};
可以在组件内部使用 errorCaptured
钩子来捕获错误。
javascriptnew Vue({
// ...
errorCaptured: function (err, vm, info) {
console.error(`Error captured: ${err.toString()}\nInfo: ${info}`);
return false; // 如果返回 false,则阻止错误向上传播
}
});
Vue 支持服务器端渲染(SSR),这对于提高首屏加载速度和 SEO 优化非常有用。
首先安装必要的依赖:
bashnpm install vue vue-server-renderer express --save
然后创建一个简单的 Express 服务器来渲染 Vue 应用。
javascriptconst Vue = require('vue');
const server = require('express')();
const renderer = require('vue-server-renderer').createRenderer();
server.get('*', (req, res) => {
const app = new Vue({
data: {
url: req.url
},
template: `<div>访问的 URL 是: {{ url }}</div>`
});
renderer.renderToString(app, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error');
return;
}
res.end(`
<!DOCTYPE html>
<html lang="en">
<head><title>Hello</title></head>
<body>${html}</body>
</html>
`);
});
});
server.listen(8080);
测试是软件开发的重要组成部分,Vue 生态系统中有许多工具可以帮助你测试你的 Vue 应用程序。
Jest 是一个流行的 JavaScript 测试框架,可以与 Vue.js 无缝集成。
首先安装相关依赖:
bashnpm install --save-dev jest @vue/test-utils vue-jest babel-jest
然后创建一个测试文件,例如 MyComponent.spec.js
:
javascriptimport { shallowMount } from '@vue/test-utils';
import MyComponent from '@/components/MyComponent.vue';
describe('MyComponent.vue', () => {
it('renders correctly', () => {
const wrapper = shallowMount(MyComponent, {
propsData: { msg: 'hello!' }
});
expect(wrapper.text()).toContain('hello!');
});
});
最后,在 package.json
中添加一个脚本来运行测试:
json"scripts": {
"test": "jest"
}
国际化是指使应用程序能够适应不同语言和地区的过程。Vue 提供了 vue-i18n 插件来简化这个过程。
bashnpm install vue-i18n
javascriptimport Vue from 'vue';
import VueI18n from 'vue-i18n';
Vue.use(VueI18n);
const i18n = new VueI18n({
locale: 'en', // 设置默认语言
messages: {
en: {
message: {
hello: 'hello world'
}
},
zh: {
message: {
hello: '你好,世界'
}
}
}
});
new Vue({
i18n,
el: '#app',
data: {
locale: 'zh'
},
watch: {
locale(val) {
this.$i18n.locale = val;
}
}
});
使用:
html<div id="app">
<p>{{ $t('message.hello') }}</p>
</div>