Vue.js 的全面介绍🔥🚀
Vue.js是一个易于使用、功能多样、性能卓越且循序渐进的用户界面构建框架。其核心库专注于构建视图层。它借鉴了Angular(例如模板语法)和React(例如虚拟 DOM)的优点,并在此基础上添加了更多增强功能。
简介
网上有很多文章,但我还是想写一篇,因为它展现了我学习新框架/库的逻辑。Vue之所以能迅速流行起来,是因为它能够适应开发者的需求。它的另一个优点是迁移到 Vue 非常容易。你只需要在页面中添加一个 script 标签就可以了。
您甚至不需要知道什么是像webpack这样的捆绑器,或者像babel这样的高级编译器,或者使用像 Vue 这样的包管理器npm
来开始使用。
它确实有一个CLI,可以帮助您构建具有各种配置选项的功能齐全的 SPA,包括 Babel、TypeScript、ESLint、PostCSS、PWA、单元测试和端到端测试。
它的 CLI 最好的一点是您不需要弹出create-react-app
就可以自定义您的配置。
开始
好了,闲话少叙,让我们开始我们的第一个Vue应用吧。我会从最简单的方法开始。我们先创建一个简单的 HTML 页面:
<html>
<body>
<div id="my-vue-app">
<p>{{ hello }}</p>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
new Vue({
el: '#my-vue-app',
data: {
hello: 'Hello World!'
}
})
</script>
</body>
</html>
不管你信不信,以上就是你的第一个Vue应用启动运行所需的全部步骤。现在,我们来分解一下,看看到底发生了什么。
您首先看到的是一个段落,其中包含对名为 的变量的模板引用hello
,类似于 Angular。这意味着该值将被替换为Vue。然后我们导入脚本,UNPKG
该脚本在 之上构建了一个 CDN(内容分发网络)npm
。
然后,在第二个脚本标签中,我们创建一个新的Vue实例,并告诉它使用一个 id 为 的 DOM 元素#my-vue-app
。Vue将控制此元素及其子元素。最后,我们指定一个带有属性的数据对象。Vuehello
会在模板中替换此变量。因此,当您在浏览器中打开此文件时,您应该会看到一个带有 id 的页面Hello World!
。
请注意,我们没有使用this.data.hello
访问变量,这是因为Vue会自动使数据的每个属性都像高级变量一样可访问。
您可以在 CodePen 👇🏼 中实时查看此示例:
使用 CLI
现在,并非所有应用程序都像我们的 hello world 一样简单,因此我们需要了解Vue CLI,它可以帮助您从头开始构建完整的应用程序。在VS Code中打开终端,导航到您选择的文件夹并运行以下命令:
npx @vue/cli create my-cli-app
或者,您可以全局安装它:
npm i -g @vue/cli
vue create create my-cli-app
运行该命令时,系统会提示你选择一个预设。你可以选择基于Babel
和 的默认预设ESList
,也可以选择自定义预设,这样你可以有更多选择,例如 TypeScript、CSS 预处理器等。
由于本介绍的重点是 Vue 本身,因此我不会深入探讨 CLI 的细节,请访问其官方网站以获取有关如何使用 CLI 的更多信息。
当新应用程序创建完成后,您将得到如下文件夹结构:
您不需要关注所有这些文件,只需知道index.html
包含Vue要处理的内容、div
Vue实例化的位置以及包含我们默认组件的单个文件组件(我稍后会解释这一点)。src/main.ts
src/App.vue
单文件组件:
单文件组件是一个包含Vue组件所需的所有内容(HTML、CSS 和 JavaScript)的文件。您甚至可以将样式限定在组件内,以避免与其他组件发生不必要的样式冲突。某种程度上,它类似于Shadow DOM。
如果你查看App.vue
文件中的 script 标签,你会发现它只是定义了一个组件,其中包含另一个HelloWorld
引用自其他文件的组件。Hello world 组件是另一个单文件组件,它被传递了一个 props 参数,并显示在模板中。
我现在不会再进一步阐述这一点,但你明白我的意思了。
要运行该应用程序,只需打开 type npm run serve
。你应该看到如下页面:
Vue 根组件
现在我们已经了解了如何开始,让我们深入研究Vue的构建块。我们应该从它的根实例开始。
new Vue({
el: '#vue-app',
data: {
name: 'Yaser'
},
computed: {
fullName: function() {
return this.name + 'Adel';
}
},
watch: {
name: function(oldVal, newVal) {
console.log(`Name changed from ${oldVal} to ${newVal}`)
}
},
methods: {
nickName: function() {
return this.name === 'Yaser' ? 'Yashints' : 'NA';
}
},
created: function() {
console.log(`${this.name}`);
}
...
})
好的,这里发生了很多事情,所以让我们逐一分解。
埃尔
这是我们希望Vue使用的元素的 id 选择器。
数据
此对象包含您想要在应用程序中维护的任何属性。您可以在模板中通过属性名称获取它们的值。这之所以有效,是因为Vue会自动使所有属性在高级this
上下文中可访问。
计算
有时你的模板中会有太多的逻辑,请看这个虚构的例子:
<div id="my-component">
{{ name.split('').reverse().join('') }}
</div>
在这种情况下,运行应用程序时会看到resaY
,但在模板中包含这些函数调用并不是一个好习惯。您可以创建一个计算属性,在模板之外的其他位置处理所有这些逻辑。
var vm = new Vue({
el: '#my-component',
data: {
name: 'Yaser'
},
computed: {
// a computed getter
reversedName: function () {
// `this` points to the vm instance
return this.name.split('').reverse().join('')
}
}
})
在您的模板中,您只需:
<div id="my-component">
{{ reversedName }}
</div>
小心计算属性,这些属性是根据其依赖项的值进行缓存的,这意味着只有在值发生变化时才会重新评估。
这意味着下面的代码不会返回您所想的结果:
computed: {
now: function () {
return Date.now()
}
}
这是因为Date.now()
它不是一种反应性依赖。
方法
方法是一种简单的函数,它能让你处理诸如点击和输入变化之类的事件。除此之外,你还可以将它们用于许多其他用途,但其主要用途是事件处理。
您可能会说我们可以使用一种方法来实现前面的计算属性:
<div id="my-component">
{{ reversedName() }}
</div>
methods: {
reverseName: function () {
return this.name.split('').reverse().join('')
}
}
最终结果完全相同,但不同之处在于计算属性会根据其对应的依赖关系进行缓存。这意味着计算属性只有在依赖关系发生变化时才会重新计算,而该方法无论如何都会被调用。
处理事件的理想方法是:
<div id="app">
<button @click="sayhi">Hi</button>
<p>{{ message }}</p>
</div>
你的组件将具有:
new Vue({
el: '#app',
data() {
return {
message: null
}
},
methods: {
sayhi() {
this.message = 'Hey you!'
}
}
})
到目前为止,您还没有看到 指令@click
。我将在本文后面详细介绍指令,但这是 的简写v-on:click
。
生命周期钩子
我在上面的代码片段中定义的函数created
只是使用Vue时可以访问的众多生命周期钩子之一。可以将其视为每个组件实例化时必须经历的步骤。例如数据观察、模板编译、将实例挂载到 DOM、数据更改时更新 DOM 等等。
例如,created
可以使用钩子在创建实例时运行一段代码。
⚠️ 注意,到目前为止,我还没有在任何示例中使用箭头函数。这是因为如果使用它们,您将失去对组件上下文 或 的访问权限。如果您碰巧遇到或
this
这样的错误,那是因为您使用了箭头函数。Uncaught TypeError: Cannot read property of undefined
Uncaught TypeError: this.myMethod is not a function
您可以在官方文档中查看可用钩子的完整列表。
Vue 组件
正如你之前所见,Vue允许你定义组件并复用它们,就像 React 一样。然而,你应该知道,所有这些都是Vue本身的可复用实例。
可以使用Vuecomponent
的方法来定义一个组件:
Vue.component('my-name', { /* options */ })
由于每个组件都是Vue的一个实例,因此您可以使用除 之外的所有上述属性el
。
第一个参数是组件的名称,您将在模板中使用该名称将此组件添加到页面。
请参阅W3C 规则,了解应使用什么命名结构来防止与当前和未来的 HTML 元素发生冲突。
当您使用方法时,您正在创建全局组件,它可以在任何根VueVue.component
实例的模板中使用。
本地组件
有时,出于隔离的目的,你希望某个组件只能在应用程序的某个特定区域内访问。在这种情况下,你可以使用本地组件:
var ComponentA = { /* `... */ }`
进而:
new Vue({
el: '#app',
components: {
'component-a': ComponentA
}
})
您可以拥有任意数量的本地组件。每个属性的键是组件的名称,值是该组件的选项对象。
💡 本地组件在子组件中不可用。但你可以通过显式地将它们添加到子组件中来使其可用。
如果您想让本地组件在子组件中可用,只需明确添加它们:
var ComponentA = { /* `... */ }`
var ComponentB = {
components: {
'component-a': ComponentA
},
// ...
}
道具
与其他框架一样,Vue支持将 props 传递给组件,以实现从父级到子级的单向通信。
Vue.component('search', {
// camelCase in JavaScript
props: ['searchTerm'],
template: `
<span>{{ searchTerm }}</span>
<div>
...
</div>
`
})
<search search-term="javascript"></search>
请注意,HTML 属性不区分大小写,浏览器会将任何大写字母视为小写字母。因此,如果您使用驼峰命名的 prop 名称,则需要像上面一样使用相应的短横线命名。
您还可以传递多个道具:
props: ['searchTerm', 'filter', 'sortOrder']
如果您使用的是 TypeScript,您可能需要定义每个 prop 的类型,在这种情况下,您可以使用对象而不是数组,其中键是 prop 名称,值是类型:
props: {
searchTerm: String,
filter: Number,
sortOrder: Boolean,
}
您可以使用非原始类型,例如Array
,,,,等。Object
Function
Promise
单文件组件
好了,现在来看看什么是单文件组件。正如我之前提到的,它们包含组件所需的一切:
// component.vue
<template>
<p>{{ greeting }} World!</p>
</template>
<script>
module.exports = {
data: function () {
return {
greeting: 'Hello'
}
}
}
</script>
<style scoped>
p {
font-size: 2em;
text-align: center;
}
</style>
使用单文件组件最重要的好处是:
- 完整的语法高亮(你需要一个类似
Vetur
VS Code 的扩展) - CommonJS 模块,这意味着您可以使用以下方式将您的组件导入到其他组件中
require
- 组件范围的 CSS
您还可以将 ES6 模块与 一起使用Bug
,并且Babel
可以使用 CLI 进行设置:
<template>
<p>{{ greeting }} World!</p>
</template>
<script>
import OtherComponent from './OtherComponent.vue'
export default {
components: {
OtherComponent
},
data () {
return {
greeting: 'Hello'
}
}
}
</script>
<style scoped>
p {
font-size: 2em;
text-align: center;
}
</style>
模板
到目前为止,我们刚刚介绍了Vue实例和组件。但任何组件最重要的部分之一是它的模板。Vue使用类似于 Angular 语法的插值进行数据绑定。
<p>Message: {{ msg }}</p>
msg
对象变量的值data
在运行时被替换。
如果您只想执行一次插值,请使用v-once
指令(我们将很快回顾指令):
<p v-once>Message: {{ msg }}</p>
在这种情况下,如果您更改后者的值msg
,模板将不会改变。
原始 HTML
如果你想渲染原始 HTML,你可能知道,出于安全原因,不建议在常规插值中使用它。在 Angular 中,你可以使用innerHTML
属性,并使用 管道将其固定DomSanitizer
。在 React 中,你可以使用<div dangerouslySetInnerHTML={createMarkup()} />
。在Vuev-html
中,使用指令非常简单:
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
属性
您不能在 HTML 属性中使用插值,而是需要使用v-bind
指令:
<div v-bind:name="dynamicName"></div>
💡 如果您使用
v-bind
布尔属性,例如disabled
,v-bind
则当值为、或时将不包括null
该undefined
属性false
。
JS 表达式
您可以在数据绑定中使用表达式:
<div>{{ number + 1 }}</div>
<div>{{ ok ? 'YES' : 'NO' }}</div>
<div>{{ message.split('').reverse().join('') }}</div>
<div v-bind:id="'list-' + id"></div>
正如我之前提到的,不要在模板中使用太多逻辑,而是使用方法或计算属性。
指令
到目前为止,我们已经了解了几个指令,但Vue提供的指令远不止这些。指令以 开头v-
,但一些最常用的指令也有缩写形式,就像@click
我们之前看到的那样。几乎所有指令的值都应该是一个JavaScript 表达式,除了v-for
。
<p v-if="error">📛 Something horrible happened!</p>
参数
一些指令带有参数,这些参数在名称后使用冒号:
<a v-bind:href="url"> ... </a>
你甚至可以使用动态表达式作为指令的参数。但此功能在v2.6.0中才引入。
<a v-bind:[attributeName]="url"> ... </a>
修饰符
修饰符是位于指令名称之后的后缀,以点分隔。
<form v-on:submit.prevent="onSubmit"> ... </form>
在上面的代码片段中,.prevent
是一个修饰符,将preventDefault()
在提交事件时被调用。
CSS 类和样式绑定
在某些情况下,你需要操作 HTML 元素的 class 列表,或者为其添加一些内联样式。你可以使用v-bind
来实现。
<div v-bind:class="{ active: isActive }"></div>
您还可以同时添加多个课程:
<div
class="message"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
您可以使用对象而不是使用内联表达式:
<div v-bind:class="classObject"></div>
和:
data: {
classObject: {
active: true,
'text-danger': false
}
}
对于内联样式,可以使用类似的方法,但不是使用类,而是使用样式:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
您也可以像前面的示例一样使用对象。
条件渲染
我们v-if
在前面的一个例子中使用过。只有当表达式返回真值时,HTML 块才会被渲染:
<h1 v-if="awesome">Vue is awesome!</h1>
但更重要的是,您可以使用 else 块v-else
:
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
如果要在多个未嵌套的元素上使用 v-if,可以使用template
element:
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
从 2.1.0+ 版本开始,您可以使用v-else-if
指令来更改几个条件:
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
v-if
并不是Vuev-show
中唯一的条件指令,你也可以使用:
<h1 v-show="ok">Hello!</h1>
区别在于它们的 Angular 对应部分完全相同,v-show
将始终呈现元素并使用display
属性。
输入绑定
您可以使用v-model
输入、文本区域或选择元素创建双向数据绑定:
<input v-model="message" placeholder="edit me">
为了textarea
能够使用正常插值,您必须使用v-model
:
❌这行不通:
<textarea>{{text}}</textarea>
✔️ 相反:
<textarea v-model="message" placeholder="add multiple lines"></textarea>
请注意,这将忽略元素上可能添加的v-model
初始value
、checked
和属性。因此,请使用数据对象上的属性来初始化它们。selected
<input type="checkbox" id="checkbox" v-model="checked">
和:
//...
data: {
checked: true
}
对于多个复选框,您可以使用数组:
<div id='example-3'>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
和:
new Vue({
el: '#example-3',
data: {
checkedNames: []
}
})
对于选择,您可以使用单个属性(单选)或数组(多选)。
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
对于数组:
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
和:
//...
data: {
selected: []
}
最后,v-for
如果您想呈现自定义选项,可以使用。
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
渲染列表
你可以使用v-for
指令来渲染元素列表。其语法如下:item in items
items 是一个数组,item 是数组中每个元素的别名:
<ul class="navbar">
<li v-for="item in items">
<a v-bind:href="item.href" >{{item.title}}</a>
</li>
</ul>
您可以使用以下方式通过对象属性进行事件循环v-for
:
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
在你的组件中:
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
💡 Vue处理列表更新的方式有所不同。当数组更新时,Vue使用就地更新的方法。这意味着Vue不会移动 DOM 节点,而是会更新列表项以反映应渲染的内容。因此,如果您依赖表单输入值或子组件状态,则需要使用
v-bind:key
类似于trackBy
Angular 中的方法提供唯一键。
事件处理
既然我们已经了解了指令的用法,现在是时候讨论事件处理了。这是本介绍的最后一部分😉。
您可以使用它v-on
来处理元素上发生的事件。
<button v-on:click="counter += 1">Add 1</button>
您还可以使用方法来处理事件:
<button v-on:click="greet">Greet</button>
和:
methods: {
greet: function (event) {
// `this` inside methods points to the Vue instance
alert('Hello ' + this.name + '!')
// `event` is the native DOM event
if (event) {
alert(event.target.tagName)
}
}
}
如果需要访问原始事件,只需使用$event
并将其传递给方法:
<button v-on:click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
和:
// ...
methods: {
warn: function (message, event) {
// now we have access to the native event
if (event) event.preventDefault()
alert(message)
}
}
我之前简单提过修饰符。以下是你可以使用的修饰符列表:
.stop
.prevent
.capture
.self
.once
.passive
但这超出了本文的介绍范围。您可以在这里找到更多信息。
概括
这就是你开始使用Vue所需了解的全部内容。实际内容远不止我在这里提到的,但我相信你应该从小处着手,逐步深入到更高级的场景。我保证稍后会讲解一些高级主题,例如路由器、状态管理、表单处理、动画等等,敬请期待。
文章来源:https://dev.to/yashints/a-compressive-intro-to-vue-js-366j