如何构建你的第一个 Vue.js 组件 【已翻译100%】

简介:

记得当那天使用 CakePHP 开发的时候,我很喜欢它简易入门的特性。其文档不仅结构严密,详尽,而且对用户友好。多年以后,我在 Vue.js 上找到了同样的感觉。然而,与 Cake 相比,Vue 文档还有一个缺点:(缺乏)真实的项目教程。

不管框架的文档有多好,对与所有人来说都是不够的。阅读有关的概念并不是总能帮助你了解更多东西,也不能帮助你理解如何使用它们来实际做出某些事情。如果你和我一样,你会在实践过程中学到更多,在你编码的时候参考文档,因为你需要它们。

在本教程中,我们将构建一个星级评分系统组件。我们将在需要时介绍几个 Vue.js 概念,并介绍为什么要使用它们。

TL;DR: 这篇文章详细的介绍了如何使用 vue.js 和为什么使用 vue.js 。它旨在帮助掌握 Vue.js 的一些核心概念,并教你如何为未来的项目做出设计决策。如果你想了解整个思维过程,请继续阅读。否则,你可以直接查看 CodeSandbox 上的最终代码。

凉凉_
 翻译得不错哦!

入门指南

Vue.js(正确地)以一个简单的脚本引入足以开始运行,但是当你想使用single-file components,情况会有所不同。 现在,你不必这样构建组件。 你可以很容易地用 Vue.component 定义一个全局组件。

问题在于,这样做需要权衡使用字符串模板,没有 CSS 支持,也没有构建步骤(所以没有预处理器)。 然而,我们想要更深入地学习如何构建一个真正的在项目中使用的实际组件。出于这些原因,我们将使用由 Webpack 提供支持的实际设置。

为了保持简单并减少配置时间,我们将使用 vue-cli 和简单的 webpack-simple Vue.js模板。

首先,你需要全局安装 vue-cli。启动你的终端并键入以下内容:

npm install -g vue-cli

你现在可以通过几个按键生成随时可用的 Vue.js 样板。然后继续输入:

vue init webpack-simple path/to/my-project

你会碰到几个问题。 选择除“使用sass”之外的所有默认值,你应该回答 yes(y)。然后,vue-cli 将初始化项目并创建 package.json 文件。完成后,可以导航到项目目录,安装依赖关系,然后运行项目:

cd path/to/my-project npm install npm run dev

就这么简单!Webpack 将开始在端口 8080(如果可用)上为你的项目提供服务并在浏览器中启动它。如果一切顺利,你应该看到这样的欢迎页面。

凉凉_
 翻译得不错哦!

我们做到了吗?

可以说我们做到了!为了正确调试你的Vue.js组件,你需要正确的工具。 继续并安装Vue.js devtools浏览器扩展(Firefox/Chrome/Safari)。

你的第一个组件

Vue.js最好的功能之一是single-file components(SFC)。 它们允许您在一个文件中定义组件的结构,样式和行为,而不存在混合HTML,CSS和JavaScript的常见缺陷。

SFC以.vue扩展名结尾,并具有以下结构:

<template>
  <!-- Your HTML goes here -->
</template>

<script>
  /* Your JS goes here */
</script>

<style>
  /* Your CSS goes here */
</style>

让我们开始创建我们的第一个组件:在/src/components中创建一个Rating.vue文件,然后复制/粘贴上面的代码片段。然后,打开/src/main.js并调整现有的代码:

import Vue from 'vue'
import Rating from './components/Rating'

new Vue({
  el: '#app',
  template: '<Rating/>',
  components: { Rating }
})

最后,添加一些HTML代码到你的Rating.vue文件:

<template>
  <ul>
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
  </ul>
</template>

现在看看你的浏览器中的页面,你应该看到列表。Vue.js会将您的<Rating>组件附加到index.html中的#app元素。如果检查HTML,则应该看不到#app元素的符号:Vue.js将其替换为组件。

旁注:你有没有注意到你甚至不需要重新加载页面?这是因为Webpack的vue-loader带有一个热加载功能。与实时重新加载或浏览器同步相反,每次更改文件时,热重新加载都不会刷新页面。而是监视组件更改,只刷新它们,保持状态不变。

现在,我们已经花了一些时间来设置,是时候真正写出有意义的代码了。

凉凉_
 翻译得不错哦!

模板

我们将使用 vue-awesome,一个用 Font Awesome icons 构建的 Vue.js 的 SVG 图标组件。我们可以只加载我们需要的图标,使用 npm(或 Yarn)进行安装:

npm install vue-awesome

然后编辑你的组件,如下所示:

<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>

好吧,让我们慢一点,解释一下。

Vue.js 使用原生 ES6 模块来处理依赖和导出组件。<script>块中的前两行分别导入图标,所以最终捆绑包中不需要图标。第三个图标是从 vue-awesome 导入的 Icon 组件,所以你可以在你的项目中使用它。

图标是一个 Vue.js SFC,就像我们正在构建的这一个。如果你打开这个文件,你会发现它和我们的结构完全一样。

export default 模块将对象文字导出为我们组件的视图模型。我们在组件属性中注册了 Icon 组件,所以我们可以在本地使用它。

最后,我们在 HTML <template> 中使用了 Icon,并传递了一个 name 属性来定义我们想要的图标。通过将组件转换为 kebab-case(例如:MyComponent 变成 <my-component>),可以将组件用作自定义 HTML 标记。我们不需要在组件内嵌入任何东西,所以我们使用了一个自闭合标签。

旁注:你有没有注意到我们在 HTML 中添加了一个<div>标签?这是因为我们还在根级别的<span>中添加了一个计数器,Vue.js 中的组件模板只接受一个根元素。如果你不遵守,会得到一个编译错误。

凉凉_
 翻译得不错哦!

样式

如果你已经使用过 CSS,你应该知道一个主要的挑战就是要处理它的全局性。嵌套一直被认为是解决这个问题的方法。但现在我们知道它很快就会导致特殊性问题,使得样式难以覆盖,不能被重用,并且这将是一个难以衡量的噩梦。

于是发明了像 BEM 这样的方法来绕过这个问题,并且通过命名空间类来保持低的特异性。有一段时间,这是编写干净和可扩展的 CSS 的理想方法。然后,像 Vue.js 或 React 这样的框架和库就出现了,并将 scoped styling 引入表中。

React 具有样式化的组件,Vue.js 具有 scoped styling CSS。它可以让你编写特定组件的 CSS,而不必拿出一些技巧来保持它的包含结构。您使用“普通”类名编写常规 CSS,Vue.js 通过将数据属性分配给 HTML 元素并将其附加到编译样式来处理范围限定。

让我们在组件上添加一些简单的类:

<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>

和 css 样式:

<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>

看到那个scoped属性了吗? 这是告诉 Vue.js 去范围化样式,所以他们作用范围不会涵盖到其他地方。 如果您在 index.html 中正确地复制/粘贴 HTML 代码,您将注意到您的样式不适用:这是因为它们的作用域是组件。

那么预处理器呢?

Vue.js 使得从简单的 CSS 切换到您最喜欢的预处理器变得轻而易举。你所需要的只是适当的 Webpack 加载器和<style>块上的简单属性。我们在生成项目时对“使用sass”选择“是”,所以 vue-cli 已经为我们安装并配置了 sass-loader。现在,我们需要做的就是将 lang="scss" 添加到开始的<style>标签中。

现在我们可以使用 Sass 编写组件级样式,导入变量,颜色定义或混合等部分。如果您更喜欢缩进语法(或“sass”符号),只需在 lang 属性中将 scss 切换 sass 即可。

凉凉_
 翻译得不错哦!

行为

现在我们的组件看起来不错,现在是时候让它开始工作了。目前,我们有一个硬编码的模板。让我们设置一些初始的模拟状态,并调整模板,使其显示出来:

<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>

我们在这里所做的是使用 Vue 的数据来设置组件状态。你在 data 中定义的每个属性都是有响应性的:如果它发生变化,它将反映在视图中。

我们正在创建一个可重用的组件,因此 data 需要成为工厂函数而不是对象文字。这样我们就得到了一个新的对象,而不是一个可以跨几个组件共享的现有对象。

我们的 data 工厂返回两个属性:stars,当前“活动”的 star 数和 maxStars,还有一个就是组件中 star 的总数。因为我们会适配我们的模板规则,所以它反映了组件的实际状态。Vue.js 带有一堆指令,可以让您将演示逻辑添加到模板中,而无需将其与纯 JavaScript 代码混合。v-fordirective 遍历任何可迭代的对象(数组,对象文字,映射等)。它也可以把一个数字作为一个范围重复 x 次、这就是我们用 v-for="star in maxStars" 所做的,所以我们对组件中的每个星星都有一个<li>。

您可能已经注意到一些属性以冒号为前缀,这是 v-bind 指令的缩写,它将属性动态绑定到表达式。我们可以把它写成长的形式,v-bind:class。

当 star 处于活动状态时,我们需要在 <li> 元素上添加 active 类。在我们的项目下,这意味着每个 <li> 的索引小于 stars 应该有 active 类。我们在 :class 指令中使用了一个表达式,当当前 star 小于总 star 数时,才会追加 active。同样条件下我们使用三元运算符来定义 Icon 组件使用的什么样的图标:star 或 star-o。

凉凉_
 翻译得不错哦!

那计数器呢?

现在我们的 star 列表是绑定到实际的数据,现在我们是时候对计数器也执行相同的操作。最简单的方法是使用带有 mustache 语法的文本插值:

<span>{{ stars }} of {{ maxStars }}</span>

很简单,不是吗? 现在在这种况下,这是诀窍。 但是,如果我们需要一个更复杂的 JavaScript 表达式,最好将其抽象到一个计算属性中。

export default {
  ...
  computed: {
    counter() {
      return `${this.stars} of ${this.maxStars}`
    }
  }
}
/* ... */
<span>{{ counter }}</span>

在这里,这是矫枉过正。 我们可以避开模板内表达式,并保持可读性。然而,当你不得不处理更复杂的逻辑时,记住计算的属性。

另一件我们需要做的是提供一种方法来隐藏计数器,如果我们不需要它的时候。 最简单的方法是使用带有布尔值的 v-if 指令。

<span v-if="hasCounter">{{ stars }} of {{ maxStars }}</span>
/* ... */
export default {
  ...
  data() {
    return {
      stars: 3,
      maxStars: 5,
      hasCounter: true
    }
  }
}
凉凉_
 翻译得不错哦!

交互

我们差不多完成了,但是我们仍然需要实现组件中最有趣的部分:响应性。我们将使用 v-on,这是处理事件和方法的 Vue.js 指令,可以附加所有方法的 Vue.js 属性。

<template>
  ...
  <li @click="rate(star)" ...>
  ...
</template>
/* ... */
export default {
  ...
  methods: {
    rate(star) {
      // do stuff
    }
  }
}

我们在 <li> 上添加了 @click 属性,这是 v-on:click 的简写。该指令包含对我们在组件的 methods 属性中定义的 rate 方法的调用。

“等一下...这看起来非常像熟悉的 HTML 的 onclick 属性。在 HTML 中使用内联 JavaScript 不是一个过时和不好的做法吗?“

确实如此,但是即使语法看起来很像 onclick,但比较两者是一个错误。当你构建一个 Vue.js 组件时,你不应该把它看作是分离的 HTML/CSS/JS,而应该是一个使用多种语言的组件。当项目在浏览器中开启服务或编译生产时,所有的 HTML 和指令都被编译成普通的 JavaScript。如果您检查已渲染的 HTML,您将看不到您的指令的任何标志,也没有任何 onclick 属性。Vue.js 会编译好你的组件并创建合适的绑定。

这也是为什么您可以从模板访问组件的上下文的原因:因为指令绑定到视图模型。与具有单独 HTML 的传统项目相反,模板是组件的组成部分。

回到我们的 rate 方法。我们需要将 stars 变为 clicked 元素的索引,所以我们通过 @click 指令的索引,可以做到以下几点:

export default {
  ...
  methods: {
    rate(star) {
      this.stars = star
    }
  }
}

去查看您的浏览器页面,并尝试点击 star:它运行成功了

凉凉_
 翻译得不错哦!

如果你打开浏览器开发者工具栏中的 Vue 面板并选择 <Rating> 组件,当你点击 star 时,你会看到数据的变化。这表明你的 star 属性是响应性的:当你改变它的时候,它会把它的改变指派给视图。 这个概念被称为数据绑定,如果您使用过 Backbone.js 或 Knockout 之类的框架,您应该熟悉这个概念。 不同之处在于,Vue.js 和 React 一样,只能在一个方向上进行:这就是所谓的单向数据绑定。不过这个话题值得写一篇单独的文章。

在这一点上,我们可以认为已完成 —— 但我们可以做更多的工作来改善用户体验。

现在,我们实际上不能给出 0 的等级,因为点击一个 star 会将它的比率设置为它的索引。更好的方案是重新点击同一颗 star,并切换至其当前状态,而不是保持 active 状态。

export default {
  ...
  methods: {
    rate(star) {
      this.stars = this.stars === star ? star - 1 : star
    }
  }
}

现在,如果点击的 star 的索引等于 star 当前值,我们就减少它的值。 否则,我们给它分配 star 值。

如果我们想要彻底解决,我们还应该添加一个控制层,以确保 star 从来没有被赋予一个没有意义的值。我们需要确保 star 永远不会小于 0,也绝不会比 maxStars 更大,而且它是一个合适的数字。

export default {
  ...
  methods: {
    rate(star) {
      if (typeof star === 'number' && star <= this.maxStars && star >= 0) {
        this.stars = this.stars === star ? star - 1 : star
      }
    }
  }
}
凉凉_
 翻译得不错哦!

传递 props 属性

现在,组件的数据在数据属性中被硬编码。如果我们希望我们的组件实际上是可用的,我们需要能够从其实例传递自定义数据。在 Vue.js 中,我们用 props 做到这一点。

export default {
  props: ['grade', 'maxStars', 'hasCounter'],
  data() {
    return {
      stars: this.grade
    }
  },
  ...
}

和在 main.js 文件里:

new Vue({
  el: '#app',
  template: '<Rating :grade="3" :maxStars="5" :hasCounter="true"/>',
  components: { Rating }
})

这里有三件事要注意:

首先,我们使用 v-bind 简写从组件实例传递 props 属性:这就是 Vue.js 所谓的动态语法。当你想要传递一个字符串值时,你不需要知道它的具体值,为此,字面值语法(没有 v-bind 的普通属性)将起作用。但对我们而言,由于我们正在传递数字和布尔值,所以这很重要。

props 和数据属性在编译时被合并,所以我们不需要改变在视图模型或模板中调用属性的方式。出于同样的原因,我们不能在 props 数据属性中使用相同的名称。

最后,我们定义了一个级别属性,并将其作为 star 数值属性中的值传递给它。我们之所以这样做,不是直接使用级别属性,而是因为级别改变,值会发生变化。在 Vue.js 中,props 从父级传递给子级,而不是反过来传递,所以你不会改变父级的状态。这将违背 单向数据流 的原则,使事情难以调试。这就是为什么你不应该试图改变子组件内的 prop。相反,定义一个使用 props 的初始值作为自声的本地数据属性。

最后的润色

在这一天马上过去之前,我们应该了解 Vue.js 最后一个惊奇的地方:prop 的验证。

Vue.js 允许你在传递给组件之前控制 prop。您可以执行四个主要的事情:检查类型,要求定义一个 prop 属性,设置默认值,并执行自定义验证

export default {
  props: {
    grade: {
      type: Number,
      required: true
    },
    maxStars: {
      type: Number,
      default5
    },
    hasCounter: {
      type: Boolean,
      defaulttrue
    }
  },
  ...
}

我们使用类型检查来确保将正确类型的数据传递给组件。这将对我们忘记使用动态语法来传递非字符串值的错误特别有用。我们也确保通过要求它填写 grade 属性。对于其他 props 属性,我们定义了默认值,所以即使没有传递自定义数据,组件也能正常工作。

现在我们可以简单地通过执行以下操作来实例化组件:

<Rating :grade="3"/>

就是这样!您刚刚创建了第一个 Vue.js 组件,并探索了许多概念


本文作者:凉凉_

本文发布时间:2018年01月29日

本文来自云栖社区合作伙伴CSDN,了解相关信息可以关注csdn.net网站。

目录
相关文章
|
21天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js:从零开始构建后端服务
【10月更文挑战第42天】在数字时代的浪潮中,掌握一门后端技术对于开发者来说至关重要。Node.js,作为一种基于Chrome V8引擎的JavaScript运行环境,允许开发者使用JavaScript编写服务器端代码,极大地拓宽了前端开发者的技能边界。本文将从Node.js的基础概念讲起,逐步引导读者理解其事件驱动、非阻塞I/O模型的核心原理,并指导如何在实战中应用这些知识构建高效、可扩展的后端服务。通过深入浅出的方式,我们将一起探索Node.js的魅力和潜力,解锁更多可能。
|
13天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
117 64
|
16天前
|
JSON 缓存 JavaScript
深入浅出:使用Node.js构建RESTful API
在这个数字时代,API已成为软件开发的基石之一。本文旨在引导初学者通过Node.js和Express框架快速搭建一个功能完备的RESTful API。我们将从零开始,逐步深入,不仅涉及代码编写,还包括设计原则、最佳实践及调试技巧。无论你是初探后端开发,还是希望扩展你的技术栈,这篇文章都将是你的理想指南。
|
9天前
|
JSON JavaScript 前端开发
深入浅出Node.js:从零开始构建RESTful API
在数字化时代的浪潮中,后端开发作为连接用户与数据的桥梁,扮演着至关重要的角色。本文将引导您步入Node.js的奇妙世界,通过实践操作,掌握如何使用这一强大的JavaScript运行时环境构建高效、可扩展的RESTful API。我们将一同探索Express框架的使用,学习如何设计API端点,处理数据请求,并实现身份验证机制,最终部署我们的成果到云服务器上。无论您是初学者还是有一定基础的开发者,这篇文章都将为您打开一扇通往后端开发深层知识的大门。
26 12
|
13天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
24 8
|
13天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
16天前
|
JavaScript NoSQL API
深入浅出Node.js:从零开始构建RESTful API
在数字化时代的浪潮中,后端开发如同一座灯塔,指引着数据的海洋。本文将带你航行在Node.js的海域,探索如何从一张白纸到完成一个功能完备的RESTful API。我们将一起学习如何搭建开发环境、设计API结构、处理数据请求与响应,以及实现数据库交互。准备好了吗?启航吧!
|
19天前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
28 5
|
18天前
|
缓存 负载均衡 JavaScript
构建高效后端服务:Node.js与Express框架实践
在数字化时代的浪潮中,后端服务的重要性不言而喻。本文将通过深入浅出的方式介绍如何利用Node.js及其强大的Express框架来搭建一个高效的后端服务。我们将从零开始,逐步深入,不仅涉及基础的代码编写,更会探讨如何优化性能和处理高并发场景。无论你是后端新手还是希望提高现有技能的开发者,这篇文章都将为你提供宝贵的知识和启示。
|
1月前
|
JavaScript 中间件 关系型数据库
构建高效的后端服务:Node.js 与 Express 的实践指南
在后端开发领域,Node.js 与 Express 的组合因其轻量级和高效性而广受欢迎。本文将深入探讨如何利用这一组合构建高性能的后端服务。我们将从 Node.js 的事件驱动和非阻塞 I/O 模型出发,解释其如何优化网络请求处理。接着,通过 Express 框架的简洁 API,展示如何快速搭建 RESTful API。文章还将涉及中间件的使用,以及如何结合 MySQL 数据库进行数据操作。最后,我们将讨论性能优化技巧,包括异步编程模式和缓存策略,以确保服务的稳定性和扩展性。