在Vue中,我们有两种主要的API风格,分别是Vue 2的选项式API(Options API)和Vue 3的组合式API(Composition API)。这两种API风格代表了Vue.js在不同版本中的演进和发展,为开发者提供了不同的开发方式和编码体验。
选项式 API 是Vue 2.x 版本中主流的开发方式,它通过一系列选项(options)的配置来定义组件的各个部分,包括数据、计算属性、方法、生命周期钩子等。这种方式的特点是简单直观,适合小型项目和初学者,同时也为开发者提供了很好的可维护性和可扩展性。
Vue3推出了 Composition 组合式API,那么为什么还要学 Vue2 的 Options 选项式 API ?
- 熟悉度: 选项式 API 是 Vue 2.x 版本一直沿用的 API,许多现有的项目和文档都基于这种风格。许多开发者已经对选项式 API 有了很深的理解,学习成本相对较低。
- 简单直观: 对于小型项目或初学者来说,选项式 API 提供了一种简单、直观的方式来组织组件代码。它是一种很好的入门方式,使得初学者更容易理解 Vue 的基本概念。
- 生态系统支持: 由于选项式 API 是 Vue 2.x 主流的 API 风格,许多第三方库和工具都基于它开发。这意味着在使用这些库和工具时,更容易找到相关的文档和支持。
学习选项式 API 和组合式 API 都是很有价值的,它们有不同的优势和适用场景。对于小白,选项式 API 更为直观简单。
在这篇文章中,我们将原生 JS 和 Vue 进行一些比较,以便大家更好地理解选项式 API。
Options API
Vue官网罗列了非常多选项式API,我们可以结合官网进行学习。通过结合官方文档,我们可以更系统地学习每个选项式 API 的用法和最佳实践。
详情请见:API 参考 | Vue.js (vuejs.org)
1. 数据管理 - data
在原生 JS 中,我们通常需要手动管理 DOM 元素和数据的关系,这意味着我们必须亲自处理如何将数据展示到网页上。
一个简单的例子:
html
<body>
<div id="app"></div>
</body>
<script>
const app = document.getElementById('app');
let message = 'Hello JavaScript!';
app.innerHTML = message;
</script>
这里,我们通过获取id
为app
的容器,手动声明我们要插入的内容,然后进行挂载。
这是原生js的写法,显然效率很低,每次都要手动获取dom结构,然后声明,再挂载。当数据变得复杂时,这种手动管理方式显得混乱而不方便。
那么在 Vue 中,为了提高开发效率,就允许我们将数据集中到一个称为 data
的容器中,然后在需要的时候直接进行挂载。
html
<body>
<div id="app"></div>
</body>
<script>
const app = Vue.createApp({
template:'{{message}}',
data() {
return {
message: 'Hello Vue!'
};
}
}).mount('#app')
</script>
这里,我们使用 Vue 的 createApp
方法创建了一个Vue应用,定义了一个数据属性 message
,并给它一个初始值。这样,我们就能在模板中直接使用这个数据,并实现动态显示内容,而不用像原生JS一样手动管理DOM元素和数据的关系,让代码更容易维护。
2. 方法 - methods
在原生 JS 中,我们通常需要手动定义函数来处理交互和事件。
html
<body>
<div id="app">
<h2 id="count">0</h2>
<button id="add">+1</button>
</div>
</body>
<script>
const countElement = document.getElementById('count');
const addButton = document.getElementById('add');
let count = 0;
function add() {
count++;
countElement.innerHTML = count;
}
addButton.addEventListener('click', add);
</script>
在这个页面中,我想实现一个点击按钮,页面上的数字就加一,在原生JS中,我们就只能分别获取他们的dom结构,然后给按钮添加一个点击事件。
那么我们来看一下Vue的是怎么实现的:
类似于data
,methods
这个容器,允许我们把要所有方法定义在这里。
html
<body>
<div id="app"></div>
</body>
<script>
const app = Vue.createApp({
// 模板中显示当前count的值,并有一个按钮触发+1操作
template:
`<h2>{{count}}</h2>
<button @click="add">+1</button>`,
// 数据存储
data() {
return {
count: 0
}
},
// 方法定义
methods: {
add() {
// 点击按钮时执行+1操作
this.count++;
}
}
}).mount('#app')
在这个例子中,我们定义了一个名为 changeMessage
的方法,当调用这个方法时,会改变数据属性 message
的值。
3. 计算属性 - computed
computed
选项用于定义基于数据属性计算出的属性,这些属性的值会自动根据相关数据的变化而更新。
举个例子来说,我们有两个值,value
和 square
(为value
的平方),还有一个按钮,当点击按钮时,调用updateValue
方法,使得 value
的值加一,并且对应的square
值也对应变化。
原生JS实现:
html
<div id="app">
<p id="value">数值: 0</p>
<p id="square">平方: 0</p>
<button id="updateBtn"> +1 </button>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
let value = 0;
const valueElement = document.getElementById('value');
const squareElement = document.getElementById('square');
const updateBtn = document.getElementById('updateBtn');
function updateValue() {
value += 1;
valueElement.textContent = '数值: ' + value;
squareElement.textContent = '平方: ' + (value * value);
}
updateBtn.addEventListener('click', updateValue);
});
</script>
在原生 JS 的例子中,我们手动管理了值的变化和更新,每次点击按钮时,我们通过更新 DOM 的方式显示新的值。
vue 实现:
html
<div id="app">
<p>数值: {{ value }}</p>
<p>平方: {{ square }}</p>
<button @click="updateValue">+1</button>
</div>
<script>
const app = Vue.createApp({
template: '#app',
data: {
value: 0
},
computed: {
square() {
return this.value * this.value;
}
},
methods: {
updateValue() {
this.value += 1;
}
}
}).mount('#app')
</script>
我们使用 computed
属性 square
来计算 value
的平方,模板中直接引用这个 computed
属性。这样,每次点击按钮时,value
的变化都会自动更新 square
的值。
4. 监听数据变化 - watch
watch
选项用于监听数据的变化,并在数据变化时执行特定的操作。同样的操作computed
能做的watch
也都能做。
html
<div id="app">
<p>数值: {{ value }}</p>
<p>平方: {{ square }}</p>
<button @click="updateValue">+1</button>
</div>
<script>
const app = Vue.createApp({
template: '#app',
data: {
value: 0
},
computed: {
square() {
return this.value * this.value;
}
},
watch: {
value(newValue) {
this.square = newValue * newValue;
}
}
}).mount('#app')
</script>
那么computed
和watch
的区别在哪呢?
computed
是一个计算属性,它根据已有的数据计算出一个新的值,并将这个值缓存起来,只有当依赖的数据发生变化时,才会重新计算。
- 简洁方便:computed 计算属性的定义方式和普通属性一样,不需要额外的方法调用。
- 自动缓存:computed 的计算结果会被缓存起来,只有当依赖的数据发生变化时,才会重新计算,减少了重复计算的开销。
- 响应式:computed 的计算结果是响应式的,当依赖的数据发生变化时,会自动更新计算结果,并触发相关的视图更新。
watch
是一个观察者,它可以监听一个数据的变化,并在数据变化时执行相应的回调函数。
- 灵活性:watch 可以监听任意数据的变化,不限于计算属性的依赖关系。
- 异步操作:watch 可以执行异步操作,比如发送网络请求或者执行复杂的计算。
- 更深入的监听:watch 可以监听对象或数组的变化,并通过深度监听选项来实现。
综上所述,computed
适用于计算属性的场景,能够简化代码并提高性能;而 watch
适用于需要更灵活的监听和异步操作的场景。在实际使用中,可以根据具体的需求选择合适的方式来观察数据的变化。
5. 子组件接收父组件传的值 - props
有时,我们需要从父组件向子组件传递数据。这时就可以使用 props
选项。
props
是 Vue 组件之间进行数据传递的一种机制,它允许父组件向子组件传递数据。通过 props
,你可以将数据从父组件传递到子组件,实现组件之间的通信。以下是一个详细的例子,演示如何使用 props
:
假设我们有一个父组件 Parent
,和一个子组件 Child
。我们希望在父组件中传递一个消息给子组件,并让子组件显示这个消息。
html
<!-- Parent.vue -->
<template>
<div>
<h1>父组件</h1>
<!-- 使用 Child 子组件,并传递消息 -->
<Child parentMsg="Hello from parent!"></Child>
</div>
</template>
<script>
import Child from './Child.vue';
export default {
components: {
Child
}
};
</script>
在 Parent
中,我们引入了 Child
组件,并在模板中使用它。通过 parentMsg
属性,我们向子组件传递了一个字符串消息。
现在,让我们看一下 Child
子组件如何接收并显示这个消息:
html
<!-- Child.vue -->
<template>
<div>
<h2>子组件</h2>
<!-- 显示通过 props 接收到的消息 -->
<p>{{ parentMsg }}</p>
</div>
</template>
<script>
export default {
// 声明接收的 props
props: {
parentMsg: String
}
};
</script>
在 Child
中,我们使用了 props
选项声明了一个名为 parentMsg
的 prop,并指定了它的类型为 String
。这样,Child
就能够接收从父组件传递过来的消息,并在模板中显示出来。
6. 父组件接收子组件传的值 - $emit()
$emit()
是一个用于触发自定义事件的方法。通过 $emit()
方法,你可以在子组件中触发一个自定义事件,并向父组件传递数据。
举个例子,这里我们通过子组件向父组件传 Hello from child!
这段话,父组件接收。
html
<template>
<div>
<h2>子组件</h2>
<button @click="submit">子向父传值</button>
</div>
</template>
<script>
export default {
methods: {
submit() {
// 使用 emit 触发名为 'event' 的自定义事件,并传递一些数据
this.$emit('event', 'Hello from child!');
}
}
};
</script>
在子组件中,有一个按钮,当按钮被点击时,通过 submit
方法,使用 $emit()
触发了自定义事件'event'
,并传递了字符串 'Hello from child!'
作为数据。
html
<template>
<div>
<h2>父组件</h2>
<Child @event="handle" />
<!-- 在父组件中通过监听 'event' 自定义事件 -->
</div>
</template>
<script>
import Child from './Child.vue';
export default {
components: {
Child
},
methods: {
handle(data) {
// 处理来自子组件的数据
console.log('接收到子组件的数据', data);
}
}
};
</script>
在父组件中,引入了子组件 <Child/>
,并通过 @event
监听了子组件触发的名为 'event'
的自定义事件。随后调用 handle
的方法,打印接收来自子组件的数据。
7. 生命周期钩子
Vue 提供了一系列的生命周期钩子函数,这些钩子函数允许开发者在组件的不同阶段执行自定义的逻辑。以下是几个常见的生命周期钩子函数:
-
beforeCreate: 在组件实例被创建之前被调用。可以在这里进行一些组件实例的初始化工作,但此时还没有访问到数据和方法。
-
created: 在组件实例创建完成后被调用。通常用于发起数据请求、初始化数据等操作,此时已经可以访问到数据和方法。
-
beforeMount: 在组件挂载之前被调用。可以在这里进行一些 DOM 操作,但此时组件还没有真正挂载到页面上。
-
mounted: 在组件挂载完成后被调用。通常用于获取已经挂载的 DOM 元素,执行一些需要在页面上操作的逻辑。
-
beforeUpdate: 在数据更新之前被调用。可以在这里做一些数据更新前的准备工作,但需要注意避免直接修改数据,以防止死循环。
每个生命周期钩子触发的时机都不相同,我们可以根据业务的需求,选择对应的钩子函数,比如,如果我想在跳转页面后立马弹出一个广告,那么可以用到mounted
。
html
<script>
mounted() {
// 在组件挂载后触发弹出广告的逻辑
this.showAdvertisement();
},
methods: {
showAdvertisement() {
// 在这里触发弹出广告的具体逻辑
alert('弹出广告:金石计划进行中!');
}
}
</script>
最后
看到这里,相信你对Vue选项式 API 已经有所了解,本文介绍的只是选项式API的冰山一角,所有的 API 还请查阅官网文档。
在阅读官方文档时,我们可以按照自己的学习节奏,逐步掌握每个选项的用法,并通过实际的例子进行练习。这样的学习方式既能够帮助小白开发者快速上手,又能够建立对 Vue 选项式 API 的深刻理解。
已将学习代码上传至 github,欢迎大家学习指正!
技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 "点赞 收藏+关注" ,感谢支持!!