我记得当时我拿起CakePHP,我很喜欢,开始使用它是多么容易。这些文档不仅结构合理,详尽无遗,而且用户友好。多年以后,这正是我在Vue.js中感受到的。然而,与Cake相比,Vue文档仍然缺少一件事:一个真实的项目教程。
无论框架的文档记录如何,这对每个人来说都是不够的。阅读概念并不总是有助于了解大局或了解如何使用它们来实际制作某些东西。如果您像我一样,通过制作一些可用的组件来更好地学习,并在编码时参考文档,帮助记忆文档和熟练使用Vue。
在本教程中,我们将构建星级评分系统组件。我们将学习几种Vue.js中的概念,我们会在项目中使用到他们,并将讨论为什么我们使用它们。
这篇文章深入介绍了如何以及为何。它旨在帮助您掌握Vue.js的一些核心概念,并教您如何为未来的项目做出设计决策。如果您想了解整个思考过程,请继续阅读。否则,您可以查看CodeSandbox上的最终代码。
入门Vue.js,当然你会以自己作为一个简单的脚本运行而觉得已经不错了,但是当你想使用单文件组件时情况有点不同。当然,你不一定必须构建以组件的这种方式。您可以完美地使用定义全局组件Vue.component。问题是,这需要权衡,例如必须使用字符串模板,没有范围的CSS支持,也没有构建步骤(因此,没有预处理器)。然而,我们希望更深入地学习如何构建一个可以在实际项目中使用的实际组件。出于这些原因,我们将采用由Webpack提供支持的实际设置。
为了简化操作并缩短配置时间,我们将使用vue-cli和webpack-simple Vue.js模板。
首先,您需要在全局安装vue-cli。启动终端并键入以下内容:
npm install -g vue-cli
您需要继续输入:
vue init webpack-simple path/to/my-project
你会在这个过程中被问到几个问题。选择除“使用sass”以外的所有内容,都是为默认值。然后,vue-cli将初始化项目并创建package.json文件。完成后,您可以导航到项目的目录,安装依赖项并运行项目:
cd path/to/my-project npm install npm run dev
不出意外!Webpack将开始在端口上提供项目8080(如果可用,8080端口没有被其他程序占用)并在浏览器中触发它。如果一切顺利,你应该看到像这样的欢迎页面。
几乎!要正确调试Vue.js组件,您需要正确的工具。继续安装Vue.js devtools浏览器扩展程序(Firefox / Chrome / Safari)。
你的第一个组件最好的功能之一是Vue.js单文件组件(SFC)。它们允许您在一个文件中定义组件的结构,样式和行为,而没有混合HTML,CSS和Javascript的常见缺点。
SFC以.vue扩展名结尾,具有以下结构:
让我们来创建我们的第一个组件:创建一个Rating.vue文件/src/components,然后复制/粘贴上面的代码片段。然后,打开/src/main.js并调整现有代码:
import Vue from 'vue' import Rating from './components/Rating' new Vue({ el: '#app', template: ' ', components: { Rating } })最后,为您的Rating.vue添加一些HTML:
- One
- Two
- Three
现在查看浏览器中的页面,您应该看到列表!Vue.js将您的
旁注:您是否注意到您甚至不需要重新加载页面?那是因为Webpack的vue-loader带有热重载功能。与实时重新加载或浏览器同步相反,热重新加载不会在每次更改文件时刷新页面。相反,它会监视组件更改并仅刷新它们,保持状态不变。
现在我们已经花了一些时间来设置,但现在是我们实际编写有意义的代码的时候了。
模版template我们将使用vue-awesome,一个用Font Awesome图标构建的Vue.js的SVG图标组件。这允许我们只加载我们需要的图标。继续使用npm(或Yarn)安装它:
npm install vue-awesome
然后编辑您的组件,如下所示:
3 of 5
好吧好吧,让我们放慢脚步并解释所有这些内容
Vue.js使用原生ES6模块来处理依赖项和导出组件。
模版修改:
3 of 5
我们在这里做的是使用Vue data来设置组件状态。您定义的每个属性都会跟着data中的属性进行绑定:如果它发生变化,它将反映在视图中。
我们正在制作一个可重用的组件,因此data需要是一个工厂函数而不是一个对象字面量。通过这种方式,我们获得了一个新对象,而不是对将在多个组件之间共享的现有对象的引用。
我们的data工厂返回两个属性:stars表示当前“激活”星数量,maxStars表示总的星星数量。从这些,我们调整了我们的模板,以便它反映实际组件的状态。Vue.js附带了一系列指令,可以让您在模板中添加表示逻辑,而无需将其与纯Javascript混合使用。该v-for指令遍历任何可迭代对象(数组,对象文字,映射等)。它也可以将数字作为重复x次的范围。这就是我们所做的v-for="star in maxStars",所以我们
您可能已经注意到某些属性以冒号为前缀:这是该v-bind指令的简写,它将属性动态绑定到表达式。我们本来可以用它的不省略形式写出来:v-bind:class。
当星号处于激活状态时,我们需要
既然我们的star列表与实际数据绑定,那么我们就应该为计数器做同样的事了。最简单的方法是使用“胡子语法”进行文本插值:
{{ stars }} of {{ maxStars }}很直白,不是吗?现在在我们的例子中,这可以解决问题,但如果我们需要更复杂的Javascript表达式,最好在计算属性中对其进行抽象。
export default { ... computed: { counter() { return `${this.stars} of ${this.maxStars}` } } }这里有点矫枉过正。我们可以使用模板内表达式可以保持可读性。然而,当您必须处理更复杂的逻辑时,请记住计算属性。
我们需要做的另一件事是提供一种方法来隐藏计数器,如果我们不想要它。最简单的方法是使用v-if带有布尔值的指令。
{{ stars }} of {{ maxStars }}data中添加hasCounter属性
export default { ... data() { return { stars: 3, maxStars: 5, hasCounter: true } } }我们差不多完成了,但我们仍然需要实现组件中最有趣的部分:反应性。我们将使用v-on处理事件的Vue.js指令,以及methods一个可以附加所有方法的Vue.js属性。
......
methods中
export default { ... methods: { rate(star) { // do stuff } } }我们在上面添加了一个@click属性
“等一下......这看起来非常熟悉HTML的属性。在HTML中使用内联Javascript不是一种过时的错误做法吗?“
确实如此,但即使语法看起来很像,比较两者也是一个错误。当您构建Vue.js组件时,您不应将其视为分离的HTML / CSS / JS,而应将其视为使用多种语言的一个组件。当项目在浏览器中编译后,所有HTML和指令都编译为纯Javascript。如果在浏览器中检查呈现的HTML,则不会看到任何指令的迹象,也不会看到任何属性。Vue.js编译了您的组件并创建了正确的绑定。这也是您可以直接从模板访问组件上下文的原因:因为指令绑定到视图模型。与具有单独HTML的传统项目相反,模板是组件的组成部分。
回到我们的rate方法。我们需要在click时候修改stars为当前li的索引,所以我们从@click指令传递索引,我们可以执行以下操作:
export default { ... methods: { rate(star) { this.stars = star } } }在浏览器中查看页面并尝试点击星标:它有效!
如果您在浏览器devtools中打开Vue面板并选择该
到这个点上,我们可以称之为完成,但我们可以做更多的工作来改善用户体验。
现在,我们实际上不能给出零等级,因为点击一个星标将stars设置为其索引,而li的索引永远大于0。更好的做法是重新点击同一颗星并让它切换当前状态而不是保持活跃状态。
export default { ... methods: { rate(star) { this.stars = this.stars === star ? star - 1 : star } } }现在,如果点击的星的索引等于当前值stars,我们减少它的值。否则,我们为其赋值star。
如果我们想彻底,我们还应该添加一层保护,以确保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 } } } }现在,组件的数据在data属性中是硬编码的。如果我们希望我们的组件实际可用,我们需要能够从其实例传递自定义数据。在Vue.js中,我们用props可以做到。
export default { props: ['grade', 'maxStars', 'hasCounter'], data() { return { stars: this.grade } }, ... }并在main.js:
new Vue({ el: '#app', template: ' ', components: { Rating } })这里有三件事需要注意:
首先,我们使用v-bind简写来从组件实例传递props:这就是Vue.js所谓的动态语法。当您想要传递字符串值时,您不需要它,使用文字语法(不带v-bind的正常属性)将起作用。但在我们的例子中,由于我们传递数字和布尔值,所以我们这样做很重要。
props和data特性是在编译时合并了,所以props中的属性会被视图模型中的标签绑定(如果定义了)。但出于同样的原因,我们不能使用相同的名称props和data属性,否则data中的属性会被props中的属性覆盖。
最后,我们定义了一个grade props,并通过它作为一个data的stars属性。之所以我们这样做,而不是直接使用grade props,是因为当我们改变等级时,star会发生修改。在Vue.js中,props是从父母组件传递给孩子组件,而不是相反,所以你不会意外地改变父母的状态。这将违反单向数据流原则并使事情更难调试。这就是为什么你应该不尝试修改子组件内的属性。相反,定义一个data使用prop的初始值作为自己的本地属性,也是一个很好的选择。
最后的修改我们将使用Vue.js中的一个很不错的功能: prop validation
Vue.js允许您在将数据传递给组件之前对其进行控制。您可以执行以下四项主要操作:检查类型,要求定义prop,设置默认值以及执行自定义验证。
export default { props: { grade: { type: Number, required: true }, maxStars: { type: Number, default: 5 }, hasCounter: { type: Boolean, default: true } }, ... }我们使用类型检查来确保将正确类型的数据传递给组件。如果我们忘记使用动态语法传递非字符串值,这将特别有用。我们还确保grade是符合组件的给定要求进行传递的。对于其他道具,我们定义了默认值,因此即使没有传递自定义数据,组件也能正常工作。
现在我们可以通过执行以下操作来实例化组件:
就是这样!您创建了第一个Vue.js组件,并探讨了很多概念,包括生成与样板谟VUE-CLI,单文件组件,在组件数据传递,scope style,指令,事件处理,计算属性,Vue methods,单方式数据流,props和prop validation。而这仅仅是Vue.js所提供的浅显的功能!
这是一个非常密集的教程,所以如果你不理解一切,不要担心。再次阅读,在各部分之间暂停,探索并摆弄CodeSandbox上的代码。如果您对本教程有任何疑问或评论,请不要犹豫,在微博上@我!
结尾如果您有幸已经读到这里,相信一定对您有所帮助。
本文为翻译文,并添加一些自己的讨论,很多地方不流畅,请见谅。
本文的源码rating-vue-component
作者:mdiep
链接:https://www.jianshu.com/p/d090df712746



