by Sarah Dayan
通过莎拉·达扬
如何构建第一个Vue.js组件 (How to build your first Vue.js component)
I remember when I picked up CakePHP back in the day. I loved how easy it was to get started with it. Not only were the docs well-structured and exhaustive, but they were also user-friendly. Years later, this is exactly what I found with Vue.js. Yet there’s one thing the Vue docs are still short of compared to Cake: a real-life project tutorial.
我记得那天我拿起CakePHP的时候。 我喜欢开始使用它是如此容易。 这些文档不仅结构合理且详尽无遗,而且用户友好。 几年后,这正是我在Vue.js中发现的。 但是,与Cake相比,Vue文档仍然缺少一件事: 真实的项目教程 。
No matter how well-documented a framework is, this isn’t enough for everyone. Reading about concepts doesn’t always help you see the bigger picture or understand how you can use them to actually make something. If you’re like me, you learn better by doing, and you refer to the docs while you code, as you need them.
不管框架的文档化程度如何,这对每个人来说都是不够的。 阅读概念并不总是可以帮助您看到更大的景象或了解如何运用它们实际进行创作 。 如果您像我一样,则可以从中学到更多,并且在编写代码时根据需要参考文档。
In this tutorial, we’ll build a star rating system component. We’ll visit several Vue.js concepts when we need them, and we’ll cover why we’re using them.
在本教程中,我们将构建一个星级评定系统组件。 我们将拜访几位Vue.js概念,当我们需要他们,我们将讨论为什么我们使用它们。
TL;DR: this post goes in-depth in the how and why. It’s designed to help you grasp some core concepts of Vue.js and teach you how to make design decisions for your future projects. If you want to understand the whole thought process, read on. Otherwise you can look at the final code on CodeSandbox.
TL; DR :这篇文章深入探讨了如何以及为什么。 它旨在帮助您掌握Vue.js的一些核心概念,并教您如何为将来的项目做出设计决策。 如果您想了解整个思考过程,请继续阅读。 否则,您可以在CodeSandbox上查看最终代码。
入门 (Getting started)
Vue.js (rightfully) prides itself on being runnable as a simple script include, but things are a bit different when you want to use single-file components. Now, you don’t have to build components this way. You can easily get away with defining a global component with Vue.component
.
Vue.js(理所当然)以可作为一个简单脚本include进行运行而自豪,但是当您要使用单文件组件时,情况有所不同。 现在,你不必构建组件这种方式。 您可以轻松地使用Vue.component
定义全局组件。
Problem is, this comes with tradeoffs like having to use string templates, no scoped CSS support, and no build step (so, no preprocessors). Yet, we want to go deeper and learn how to build an actual component that you could use in a real project. For those reasons, we’ll go with an actual real-life setup, powered by Webpack.
问题是,这需要权衡使用,例如必须使用字符串模板,没有范围CSS支持以及没有构建步骤(因此,没有预处理器)。 但是,我们想更深入地学习如何构建可在实际项目中使用的实际组件。 出于这些原因,我们将使用由Webpack提供支持的实际设置。
To keep things simple and reduce configuration time, we’ll use vue-cli and the webpack-simple Vue.js template.
为了简化操作并减少配置时间,我们将使用vue-cli和webpack-simple Vue.js模板。
First, you need to install vue-cli globally. Fire up your terminal and type the following:
首先,您需要全局安装vue-cli。 启动您的终端并输入以下内容:
npm install -g vue-cli
You can now generate ready-to-use Vue.js boilerplates in a few keystrokes. Go ahead and type:
现在,您可以通过几次击键生成即可使用的Vue.js样板。 继续输入:
vue init webpack-simple path/to/my-project
You’ll be asked a few questions. Choose defaults for all except “Use sass” to which you should answer yes (y
). Then, vue-cli will initialize the project and create the package.json
file. When it’s done, you can navigate to the project’s directory, install dependencies, and run the project:
您会被问到几个问题。 为除“ Use sass”之外的所有选项选择默认值,您应选择是( y
)。 然后,vue-cli将初始化项目并创建package.json
文件。 完成后,您可以导航到项目目录,安装依赖项并运行项目:
cd path/to/my-projectnpm installnpm run dev
That’s it! Webpack will start serving your project on port 8080
(if available) and fire it in your browser. If all went well, you should see a welcome page like this one.
而已! Webpack将开始在端口8080
(如果有)上为您的项目提供服务,并在浏览器中启动它。 如果一切顺利,您应该会看到这样的欢迎页面。
我们到了吗? (Are we there yet?)
Almost! To properly debug your Vue.js component, you need the right tools. Go ahead and install the Vue.js devtools browser extension (Firefox/Chrome/Safari).
几乎! 要正确调试Vue.js组件,您需要正确的工具。 继续并安装Vue.js devtools浏览器扩展( Firefox / Chrome / Safari )。
您的第一个组件 (Your first component)
One of the best Vue.js features are the single-file components (SFCs). They let you define the structure, style, and behavior of a component in one file, without the usual drawbacks of mixing HTML, CSS, and JavaScript.
Vue.js的最佳功能之一是单文件组件 (SFC)。 它们使您可以在一个文件中定义组件的结构,样式和行为,而没有混合HTML,CSS和JavaScript的通常缺点。
SFCs end with a .vue
extension and have the following structure:
SFC以.vue
扩展名结尾,并具有以下结构:
<template> <!-- Your HTML goes here --></template>
<script> /* Your JS goes here */<;/script>
<style> /* Your CSS goes here */</style>
Let’s go and make our first component: create a Rating.vue
file in /src/components
, and copy/paste the code snippet above. Then, open /src/main.js
and adapt the existing code:
让我们开始制作第一个组件:在/src/components
创建一个Rating.vue
文件,然后复制/粘贴上面的代码片段。 然后,打开/src/main.js
并修改现有代码:
import Vue from 'vue'import Rating from './components/Rating'
new Vue({ el: '#app', template: '<Rating/>', components: { Rating }})
Finally, add a little bit of HTML to your Rating.vue
:
最后,在您的Rating.vue
添加一些HTML:
<template> <ul> <li>One</li> <li>Two</li> <li>Three</li> </ul></template>
Now look at the page in your browser, and you should see the list! Vue.js attached your <Rati
ng> component to th
e #app element in inde
x.html. If you inspect the HTML, you should see no sign of th
e #app element: Vue.js replaced it with the component.
现在,在浏览器中查看页面,您应该会看到列表! Vue.js附加了<Rati
纳克>组件吨o th
é#APP eleme nt in inde
x.html。 如果检查HTML,你应该看到任何迹象Ø f th
é#APP元素:Vue.js与组件取代它。
Sidenote: have you noticed you didn’t even need to reload the page? That’s because Webpack’s vue-loader comes with a hot reload feature. Contrary to live reloading or browser syncing, hot reloading doesn’t refresh the page every time you change a file. Instead, it watches for component changes and only refreshes them, keeping state untouched.
旁注 :您是否注意到您甚至不需要重新加载页面? 这是因为Webpack的vue-loader具有热重载功能。 与实时重新加载或浏览器同步相反,每次更改文件时, 热重新加载不会刷新页面。 相反,它会监视组件更改并仅刷新它们,而不会影响状态。
Now, we’ve spent some time setting things up, but it’s time we actually write meaningful code.
现在,我们花了一些时间进行设置,但是实际上是时候编写有意义的代码了。
模板 (The template)
We’re going to use vue-awesome, an SVG icon component for Vue.js built with Font Awesome icons. This allows us to only load the icons we need. Go ahead and install it with npm (or Yarn):
我们将使用vue-awesome ,这是Vue.js的SVG图标组件,该组件使用Font Awesome icons构建。 这允许我们仅加载所需的图标。 继续并使用npm(或Yarn)安装它:
npm install vue-awesome
Then edit your component like the following:
然后像下面这样编辑您的组件:
<template> <div> <ul> <li><icon name="star"/></li> <li><icon name="star"/></li> <li><icon name="star"/></li> <li><icon name="star-o"/></li> <li><icon name="star-o"/></li> </ul> <span>3 of 5</span> </div></template>
<script>import 'vue-awesome/icons/star'import 'vue-awesome/icons/star-o'
import Icon from 'vue-awesome/components/Icon'
export default { components: { Icon }}</script>
Alright alright, let’s slow down for a moment and explain all that ?
好吧, 让我们放慢一点,并解释所有这些吗?
Vue.js uses native ES6 modules to handle dependencies and export components. The first two lines in the <scri
pt> block import icons individually, so you don’t end up with icons you don’t need in your final bundle. The third one imports th
e Icon component from vue-a
wesome so you can use it in yours.
Vue.js使用本机ES6模块来处理依赖关系并导出组件。 <scri
pt>块中的前两行分别导入图标,因此最终的捆绑包中不需要多余的图标。 第三s th
from vue-a
导入了Icon组件from vue-a
好用,因此您可以在其中使用它。
Icon
is a Vue.js SFC, like the one we’re building. If you open the file, you’ll see that it has the exact same structure as ours.
Icon
是Vue.js SFC,就像我们正在构建的那样。 如果您打开该文件,将会看到它具有与我们完全相同的结构。
The export default
block exports an object literal as our component’s view model. We registered the Icon
component in the components
property so we can use it locally in ours.
export default
块将对象文字export default
为组件的视图模型。 我们在components
属性中注册了Icon
组件,因此我们可以在本地使用它。
Finally, we used the Icon
in our HTML <templa
te> and passed it
a name property to define what icon we want. Components can be used as custom HTML tags by converting them to kebab-case (eg.: MyCom
ponent becomes <my-c
omponent>). We don’t need to nest anything inside of the component, so we used a self-closing tag.
最后,我们使用的Icon
在我们HTML <templa
TE>,并通过it
的名称属性来定义图标,我们想要的东西。 通过将组件转换为(eg.: MyCom
-case可以将它们用作自定义HTML标签(eg.: MyCom
comes <my-c
omponent>)。 我们不需要在组件内部嵌套任何内容,因此我们使用了自闭合标签。
Sidenote: have you noticed we added a wrapping <d
iv> around the HTML? That’s because we also added a counter in a
<span> at root level, and component templates in Vue.js only accept one root element. If you don’t respect that, you’ll get a compilation error.
旁注 :您是否注意到我们在HTML周围添加了环绕式<d
iv>? 这是因为我们还在根级别in a
<span>中添加了一个计数器,而Vue.js中的组件模板仅接受一个根元素。 如果您不遵守该规定,则会收到编译错误。
风格 (The style)
If you’ve worked with CSS for some time, you know that one of the main challenges is having to deal with its global nature. Nesting has long been considered the solution to this problem. Now we know it can quickly lead to specificity issues, making styles hard to override, impossible to reuse, and a nightmare to scale.
如果您使用CSS已有一段时间,那么您就会知道,主要挑战之一就是必须应对CSS的全球性。 长期以来,嵌套一直被认为是解决此问题的方法。 现在,我们知道它会Swift导致特定性问题,使样式难以覆盖,无法重用以及无法扩展的噩梦。
Methodologies like BEM were invented to circumvent this issue and keep low specificity, by namespacing classes. For a while, it’s been the ideal way to write clean and scalable CSS. Then, frameworks and libraries like Vue.js or React came along and brought scoped styling to the table.
发明了像BEM这样的方法来通过命名间隔类来规避此问题并保持较低的特异性。 一段时间以来,它一直是编写干净且可伸缩CSS的理想方法。 然后,出现了诸如Vue.js或React之类的框架和库,并将范围化样式引入表中。
React has styled components, Vue.js has component-scoped CSS. It lets you write component-specific CSS without having to come up with tricks to keep it contained. You write regular CSS with “normal” class names, and Vue.js handles scoping by assigning data-attributes to HTML elements and appending it to the compiled styles.
React具有样式化的组件,Vue.js具有组件范围CSS 。 它使您可以编写特定于组件CSS,而无需提出技巧来使其保持包含状态。 您使用“常规”类名编写常规CSS,然后Vue.js通过将数据属性分配给HTML元素并将其附加到已编译的样式来处理作用域。
Let’s add some simple classes on the component:
让我们在组件上添加一些简单的类:
<template> <div class="rating"> <ul class="list"> <li class="star active"><icon name="star"/></li> <li class="star active"><icon name="star"/></li> <li class="star active"><icon name="star"/></li> <li class="star"><icon name="star-o"/></li> <li class="star"><icon name="star-o"/></li> </ul> <span>3 of 5</span> </div></template>
And style it:
并设置样式:
<style scoped> .rating { font-family: 'Avenir', Helvetica, Arial, sans-serif; font-size: 14px; color: #a7a8a8; } .list { margin: 0 0 5px 0; padding: 0; list-style-type: none; } .list:hover .star { color: #f3d23e; } .star { display: inline-block; cursor: pointer; } .star:hover ~ .star:not(.active) { color: inherit; } .active { color: #f3d23e; }</style>
See that scoped attribute up there? That’s what tells Vue.js to scope the styles, so they won’t leak anywhere else. If you copy/paste the HTML code right in the index.html
, you’ll notice your styles won’t apply: that’s because they’re scoped to the component! ?
看到那里的范围属性了吗? 这就是告诉Vue.js定义样式范围的原因,因此它们不会在其他任何地方泄漏。 如果您直接在index.html
复制/粘贴HTML代码,您会注意到您的样式将不适用:这是因为它们的范围仅限于组件! ?
那预处理器呢? (What about preprocessors?)
Vue.js makes it a breeze to switch from plain CSS to your favorite preprocessor. All you need is the right Webpack loader and a simple attribute on the <sty
le> block. We said “yes” to “Use sass” when generating the project, so vue-cli already installed and configured sass-loader for us. Now, all we need to do is add lang=
"scss" to the opening &
lt;style> tag.
Vue.js使得从纯CSS切换到您喜欢的预处理器变得轻而易举。 您只需要正确的Webpack加载器和<sty
le>块上的简单属性即可。 在生成项目时,我们对“使用sass”说“是”,因此vue-cli已为我们安装并配置了sass- loader。 现在,我们所需要做的只是s add lang=
“ scss” s add lang=
到opening ening &
lt; style>标记中。
We can now use Sass to write component-level styles, import partials like variables, color definitions, or mixins, etc. If you prefer the indented syntax (or “sass” notation), simply switch scss
to sass
in the lang
attribute.
现在,我们可以使用Sass编写组件级样式,导入局部变量,例如变量,颜色定义或mixins等。如果您喜欢缩进的语法(或“ sass”符号),只需在lang
属性scss
切换为sass
即可。
行为 (The behavior)
Now that our component looks good, it’s time to make it work. Currently, we have a hardcoded template. Let’s set up some initial mock state and adjust the template so it reflects it:
现在我们的组件看起来不错,是时候使它工作了。 当前,我们有一个硬编码模板。 让我们设置一些初始的模拟状态并调整模板,使其反映出来:
<script> ... export default { components: { Icon }, data() { return { stars: 3, maxStars: 5 } } }<;/script>
/* ... */
<template> <div class="rating"> <ul class="list"> <li v-for="star in maxStars" :class="{ 'active': star <= stars }" class="star"> <icon :name="star <= stars ? 'star' : 'star-o'"/> </li> </ul> <span>3 of 5</span> </div></template>
What we did here is use Vue’s data
to setup component state. Every property you define in data
becomes reactive: if it changes, it will be reflected in the view.
我们在这里所做的是使用Vue的data
来设置组件状态。 您在data
定义的每个属性都会变为React性的 :如果更改,它将反映在视图中。
We’re making a reusable component, so data
needs to be a factory function instead of an object literal. This way we’re getting a fresh object instead of a reference to an existing one that would be shared across several components.
我们正在制作一个可重用的组件,因此data
需要是一种工厂功能,而不是对象文字。 这样,我们得到的是一个新对象,而不是对将在多个组件之间共享的现有对象的引用。
Our data
factory returns two properties: stars
, the current number of “active” stars, and maxStars
, the total amount of stars for the component. From these, we adapted our template so it reflects the actual component’s state. Vue.js comes with a bunch of directives that let you add presentation logic to your template without mixing it with plain JavaScript. The v-for
directive loops over any iterable object (arrays, objects literals, maps, etc.). It also can take a number as a range to be repeated x number of times. That’s what we did with v-for="star in maxStars"
, so we have an <
li> for each star in the component.
我们的data
工厂返回两个属性: stars
(当前的“活动”星形数)和maxStars
(组件的星形总数)。 通过这些,我们调整了模板,使其反映了实际组件的状态。 Vue.js带有大量指令,可让您将演示文稿逻辑添加到模板中,而无需将其与纯JavaScript混合使用。 v-for
指令循环遍历任何可迭代对象(数组,对象文字,映射等)。 它也可以取一个数字作为要重复x次数的范围。 这就是我们对v-for="star in maxStars"
,因此组件中的每个star都有一个<
li>。
You may have noticed some properties are prefixed with a colon: this is a shorthand for the v-bind
directive, which dynamically binds attributes to an expression. We could have written it in its long form, v-bind:class
.
您可能已经注意到,某些属性以冒号作为前缀:这是v-bind
指令的缩写,该指令将属性动态绑定到表达式。 我们本可以以长格式v-bind:class
编写它。
We need to append the active
class on <
li> elements when the star is active. In our case, this means ever
y <li> which index is les
s than stars should hav
e the active class. We used an expression i
n the :class directive to only a
ppend active when the
current star is les
s than stars. We used the same condition, this time with a ternary operator, to define what icon to use w
ith the Icon com
ponent: st
ar or star-o.
当星星处于活动状态时,我们需要在<
li>元素上附加active
类。 在我们的情况下,该装置ever
ý<LI>其中索引i s les
总比分寿ld hav
E中的活性类。 我们使用了EXPRES sion i
n个:类指令only a
PPEND活跃时the
电流明星我s les
总比明星。 我们使用相同的条件下,这一次与一个三元运算符,定义什么图标到u se w
第i个图标com
推迟实施nt: st
AR或星形-O。
那柜台呢? (What about the counter?)
Now that our star list is bound to actual data, it’s time we do the same for the counter. The simplest way to do this is to use text interpolation with the mustache syntax:
现在,星号列表已绑定到实际数据,是时候对计数器执行相同的操作了。 最简单的方法是使用带有胡子语法的文本插值:
<span>{{ stars }} of {{ maxStars }}</span>
Pretty straight-forward, isn’t it? Now in our case, this does the trick. But if we needed a more complex JavaScript expression, it would be better to abstract it in a computed property.
很简单,不是吗? 现在就我们而言,这就是窍门。 但是,如果我们需要更复杂JavaScript表达式,则最好将其抽象到一个计算属性中 。
export default { ... computed: { counter() { return `${this.stars} of ${this.maxStars}` } }}
/* ... */
<span>{{ counter }}</span>
Here, this is overkill. We can get away with in-template expressions and still keep things readable. Yet, keep computed properties in mind for when you have to deal with more convoluted logic.
在这里, 这太过分了 。 我们可以摆脱模板中的表达式,仍然保持可读性。 但是,在必须处理更复杂的逻辑时,请记住计算属性。
Another thing we need to do is provide a way to hide the counter if we don’t want it. The simplest way to do this is to use the v-if
directive with a boolean.
我们需要做的另一件事是提供一种如果我们不想要的话可以隐藏柜台的方法。 最简单的方法是将v-if
指令与布尔值一起使用。
<span v-if="hasCounter">{{ stars }} of {{ maxStars }}</span>
/* ... */
export default { ... data() { return { stars: 3, maxStars: 5, hasCounter: true } }}
互动性 (Interactivity)
We’re almost done, but we still have to implement the most interesting part of our component: reactivity. We’re going to use v-on
, the Vue.js directive that handles events, and methods
, a Vue.js property on which you can attach all your methods.
我们差不多完成了,但是我们仍然必须实现组件最有趣的部分: reactivity 。 我们将使用v-on
(处理事件的Vue.js指令)和methods
(可在其上附加所有方法的Vue.js属性)。
<template> ... <li @click="rate(star)" ...> ...</template>
/* ... */
export default { ... methods: { rate(star) { // do stuff } }}
We added a @click
attribute on the <
li>, which is a shorthand for v-on
:click. This directive contains a call to th
e rate method which we defined in the m
ethods property of the component.
我们在<
li>上添加了@click
属性,这是d for v-on
:click的缩写。 此指令包含一个呼叫吨o th
我们定义即速率方法n the m
的成分的编制方法属性。
“Wait a minute… this looks awfully familiar with HTML’s onclick
attribute. Isn’t it supposed to be an outdated and bad practice to use inline JavaScript in HTML?”
“等等,这看起来非常熟悉HTML的onclick
属性。 在HTML中使用内联JavaScript是否不是过时且不好的做法?”
It is indeed, but even though the syntax looks a lot like onclick
, comparing the two would be a mistake. When you’re building a Vue.js component, you shouldn’t think of it as separated HTML/CSS/JS, but rather as one component that uses several languages. When the project is served in the browser or compiled for production, all the HTML and directives are compiled into plain JavaScript. If you inspect the rendered HTML, you won’t see any sign of your directives, nor any onclick
attributes. Vue.js compiled your component and created proper bindings.
的确如此,但是即使语法看起来很像onclick
,将两者进行比较还是一个错误。 构建Vue.js组件时,不应将其视为独立HTML / CSS / JS,而应将其视为使用多种语言的一个组件。 当项目在浏览器中提供服务或进行编译以进行生产时,所有HTML和指令都将编译为纯JavaScript。 如果检查呈现HTML,将看不到指令的任何迹象,也看不到任何onclick
属性。 Vue.js编译了您的组件并创建了适当的绑定。
This is also why you have access to the context of the component right from your template: because directives are bound to the view model. Contrary to a traditional project with separate HTML, the template is an integral part of the component.
这也是为什么您可以直接从模板访问组件上下文的原因:因为指令绑定到视图模型。 与带有单独HTML的传统项目相反,模板是组件的组成部分。
Back to our rate
method. We need to mutate stars
to the index of the clicked element, so we pass the index from the @click
directive, and we can do the following:
回到我们的rate
方法。 我们需要将stars
突变为clicked元素的索引,因此我们通过@click
指令传递索引,我们可以执行以下操作:
export default { ... methods: { rate(star) { this.stars = star } }}
Go check the page in your browser and try clicking on stars: it works!
在浏览器中检查页面,然后尝试单击星号: 可以!
If you open the Vue panel in your browser devtools and select the <Rati
ng> component, you’ll see the data change as you click on stars. This shows you that your
stars property is reactive: as you mutate it, it dispatches its changes to the view. That concept is called data-binding, which you should be familiar with if you ever used frameworks like Backbone.js or Knockout. The difference is that Vue.js, like React, does it in one direction only: this is called one-way data-binding. But that topic deserves an article of its own ?
如果在浏览器devtools中打开Vue面板并选择<Rati
ng>组件,则单击星号时,数据将发生变化。 这说明您your
恒星属性已处于活动状态:当您对其进行变异时,它会将其更改分派给视图。 这个概念就是所谓的数据绑定,如果您曾经使用过Backbone.js或Knockout等框架,则应该熟悉该概念。 区别在于,Vue.js与R eact一样,仅在一个方向上执行 :这是一种单向数据输入 。 但是,该主题值得发表自己的文章吗?
At this point, we could call it done — but there’s a bit more work we could do to improve user experience.
在这一点上,我们可以称之为完成-但我们还有很多工作要做,以改善用户体验。
Right now, we can’t actually give a grade of zero, because clicking on a star sets the rate to its index. What would be better is to re-click on the same star and have it toggle its current state instead of staying active.
目前,我们实际上不能给出零等级,因为单击星号会将速率设置为其指数。 最好是重新单击同一颗星星,并使其切换其当前状态而不是保持活动状态。
export default { ... methods: { rate(star) { this.stars = this.stars === star ? star - 1 : star } }}
Now if the clicked star’s index is equal to the current value of stars
, we decrement its value. Otherwise, we assign it the value of star
.
现在,如果点击的明星的指数等于当前值stars
,我们减少它的价值。 否则,我们为其分配star
的值。
If we want to be thorough, we should also add a layer of controls to make sure stars
is never assigned a value that doesn’t make sense. We need to make sure stars
is never less than 0
, never greater than maxStars
, and that it’s a proper number.
如果我们想更彻底,还应该添加一层控件以确保stars
永远不会被分配没有意义的值。 我们需要确保stars
永远不小于0
,永远不大于maxStars
,并且它是一个适当的数字。
export default { ... methods: { rate(star) { if (typeof star === 'number' && star <= this.maxStars && star >= 0) { this.stars = this.stars === star ? star - 1 : star } } }}
传递道具 (Passing props)
Right now, the component’s data is hardcoded in the data
property. If we want our component to actually be usable, we need to be able to pass custom data to it from its instances. In Vue.js, we do that with props.
现在,组件的数据已硬编码在data
属性中。 如果我们希望组件实际可用,则需要能够从其实例向其传递自定义数据。 在Vue.js中,我们使用props来实现 。
export default { props: ['grade', 'maxStars', 'hasCounter'], data() { return { stars: this.grade } }, ...}
And in main.js
:
在main.js
:
new Vue({ el: '#app', template: '<Rating :grade="3" :maxStars="5" :hasCounter="true"/>', components: { Rating }})
There are three things to observe here:
这里有三件事要观察:
First, we used the v-bind
shorthand to pass props from the component instance: this is what Vue.js calls the dynamic syntax. You don’t need it when you want to pass a string value, for which the literal syntax (normal attribute without v-bind
) will work. But in our case, since we’re passing numbers and booleans, it’s important we do.
首先,我们使用v-bind
速记来传递组件实例中的prop:这就是Vue.js所谓的动态语法 。 当您要传递字符串值时,就不需要它,字面量语法(不带v-bind
常规属性)将适用于该字符串值。 但就我们而言,由于我们要传递数字和布尔值,所以这样做很重要。
The props
and data
properties are merged at compile time, so we don’t need to change the way we call properties either in the view model or in the template. But for that same reason, we can’t use the same names for props
and data
properties.
props
和data
属性在编译时合并,因此我们无需在视图模型或模板中更改调用属性的方式。 但是出于同样的原因,我们不能对props
和data
属性使用相同的名称。
Finally, we defined a grade
prop and passed it as a value to stars
in the data
property. The reason why we did that instead of using the grade
prop directly is that the value will be mutated when we change the grade. In Vue.js, props are passed from parents to children, not the other way around, so you don’t accidentally mutate the parent’s state. This would go against the one-way data flow principle and make things harder to debug. This is why you should not try to mutate a prop inside of a child component. Instead, define a local data
property that uses the prop’s initial value as its own.
最后,我们定义了一个grade
道具并将其作为值传递给data
属性中的stars
。 我们这样做而不是直接使用grade
道具的原因是,当我们更改等级时,该值将发生突变。 在Vue.js中,道具是从父母传递给孩子的,而不是相反的,因此您不会意外地改变父母的状态。 这将违反单向数据流原理,并使调试变得困难。 这就是为什么你不应该尝试变异子组件的Struts内。 而是定义一个使用prop的初始值作为其自身的本地data
属性。
最后的润色 (Final touches)
Before we call it a day, there’s one last piece of Vue.js goodness we should visit: prop validation.
在我们称之为一天之前,我们应该访问Vue.js的最后一件事: prop验证 。
Vue.js lets you control props before they’re passed to the component. You can perform four major things: check type, require a prop to be defined, setup default values, and perform custom validation.
Vue.js使您可以在将道具传递给组件之前对其进行控制。 您可以执行四项主要操作: 检查类型 , 需要定义道具 , 设置默认值以及执行自定义验证 。
export default { props: { grade: { type: Number, required: true }, maxStars: { type: Number, default: 5 }, hasCounter: { type: Boolean, default: true } }, ...}
We used type checking to make sure the right type of data is passed to the component. This will be especially useful if we forget to use the dynamic syntax to pass non-string values. We also made sure the grade
prop was passed by requiring it. For other props, we defined default values so the component works even if no custom data is passed.
我们使用类型检查来确保将正确的数据类型传递给组件。 如果我们忘记使用动态语法来传递非字符串值,这将特别有用。 我们还通过要求它来确保grade
道具获得通过。 对于其他道具,我们定义了默认值,因此即使没有传递自定义数据,该组件也可以工作。
Now we can instantiate the component simply by doing the following:
现在,我们只需执行以下操作即可实例化该组件:
<Rating :grade="3"/>
And that’s it! You just created your first Vue.js component, and explored many concepts including generating a boilerplate projet with vue-cli, single-file components, importing components in components, scoped styling, directives, event handlers, computed properties, custom methods, one-way data flow, props and prop validation. And that’s only scratching the surface of what Vue.js has to offer!
就是这样! 您创建了第一个Vue.js组件,并探讨了很多概念,包括生成与样板谟VUE-CLI , 单文件组件 ,在组件进口部件, 范围的造型 , 指令 , 事件处理 , 计算性能 , 自定义方法 , 单数据流方式 , 道具和道具验证 。 但这仅仅是Vue.js所提供内容的表面!
This is a pretty dense tutorial, so don’t worry if you didn’t understand everything. Read it again, pause between sections, explore and fiddle with the code on CodeSandbox. And if you have any question or remark about the tutorial, don’t hesitate to hit me up on Twitter!
这是一个非常密集的教程,所以如果您不了解所有内容,请不要担心。 再次阅读它,在各节之间停顿,探索并摆弄CodeSandbox上的代码 。 如果您对本教程有任何疑问或评论,请随时在Twitter上与我联系!
Originally published at frontstuff.io.
最初发布在frontstuff.io上 。
翻译自: https://www.freecodecamp.org/news/build-your-first-vue-js-component-2dc204bca514/