左手的世界
Rise's Blog
初识 Vue 之 - 用 Vue 组件减少代码量
如何用 Vue Components 减少重复代码量

前言

这又是一篇很基础很基础的文章。(因为我菜鸡呀.估计大佬们都去折腾算法分析什么的,只有我这个菜鸡还在天天搬砖,太难了。

本篇文章主要讲述如何用 Vue Components 减少重复代码量。

需求

博客的友链页是由一个表格构成的:

name url description
张三 https://zhangsan.com 张三的挖坑日记
李四 https://lisi.com 李四的网络日志

不行,这太简陋了。如何编写一个更好的友链页呢?

实现

那么我们就用 Bootstrap 的卡片来实现一个卡片式的友链页吧。

实现1 不用 Vue

下面我们用 Bootstrap 的卡片实现一个友链卡片。

<!--为了使代码在这个例子中更加简洁,我暂且用 style 规定了一下卡片的宽度。-->
<div class="card" style="width:20rem;">
    <div class="card-body">
        <!-- 标题 -->
        <p class="h4">张三</p>
        <!-- 描述 -->
        <p>张三的挖坑日记</p>
    </div>
    <div class="card-footer">
        <!-- 链接 -->
        <a href="https://zhangsan.com">https://zhangsan.com</a>
    </div>
</div>

实现效果如下:

张三

张三的挖坑日记

这个做法有两个缺点:

  1. 如果我们来了一位新的朋友,需要再次复制粘贴,这很不合理。
  2. 如果我们需要修改卡片的样式,我们需要手动修改 n 次(n=朋友的个数)。

实现2 Vue App

引入 Vue,利用v-for我们可以提高代码的复用性。

先定义一个 Vue App,然后把朋友们以数组的形式录入 data 中。

var app = new Vue({
  el: '#app',
  data: {
    friends: [
        {
            name: "张三",
            description: "张三的挖坑日记",
            url: "https://zhangsan.com/"
        },
        {
            name: "李四",
            description: "李四的网络日志",
            url: "https://lisi.com/"
        }
    ]
  }
})<>

然后我们用v-for遍历一下friends这个元素。

<div id="app">
    <!-- 在这里用 v-for 遍历数组内容,其实它是一个 foreach -->
    <div class="card" style="width:20rem;" v-for="friend in friends">
        <div class="card-body">
            <!-- 标题 -->
            <p class="h4">{{friend.name}}</p>
            <!-- 描述 -->
            <p>{{friend.description}}</p>
        </div>
        <div class="card-footer">
            <!-- 链接,注意 这个地方要用v-bind:href -->
            <a v- bind:href="friend.url">{{friend.url}}</a>
            <!-- 关于这一点请参见 https://cn.vuejs.org/v2/guide/syntax.html#Attribute -->
            <!-- v-bind 也可以缩写为 `:url="friend.url"` 。 -->
        </div>
    </div>
</div>

这样可以复用卡片代码,并且修改样式也很方便了。

但这个代码还是不完美:

  1. 首先,如果你有个新的朋友,却需要修改 Vue App 的 data 属性。为了 HTML 内容而修改 Javascript 是很不合理的。我们需要给 Javascript 和 HTML 解藕。
  2. 不过为这一个页面开一个 Vue App 是不是有点小题大作呢? 而且更重要的一点是,一山不容二虎,嵌套 Vue App 会导致奇怪的 Bug。(禁止套娃

实现3 Vue 组件

How can we do better?

如果有这么一种写法,就比较完美了:

<friend description="张三的挖坑日记" url="https://zhangsan.com">张三</friend>
<friend description="李四的网络日志" url="https://lisi.com">李四</friend>

很幸运的是,Vue.js 提供这种功能。

我们可以定义一个 Vue Component。这里要引入两样东西:

  1. slot 写在模板中,用来插入标签中间的数据,即<friend></friend>中间的内容。
  2. props 用于提取标签属性中的数据,如<friend url="xxx"...
Vue.component('friend',{
        // 注意一定要在这里定义 props,否则会提示 not defined 的问题。
        props:['url','description'],
        template: `
        <div class="card" style="width:20rem;">
            <div class="card-body">
                <!-- 标题,这里用了slot,目的是在这里插入“<friend>这里</friend>”的内容。 -->
                <p class="h4"><slot></slot></p>
                <!-- 描述,这里就是对“<friend description="这里"...”内容的提取。 -->
                <p>{{ description }}</p>
            </div>
            <div class="card-footer">
                <!-- 链接,同理,这个我就不用解释了。注意这里也要用 v-bind -->
                <a v-bind:href="url">{{url}}</a>
                <!-- v-bind 也可以缩写为 :url="friend.url" 。 -->
            </div>
        </div>
        `
    });

这样我们就实现了一个可复用的 Vue 组件了,而且上面的问题我们已经完美解决了:

  1. 如果我们新增了一个朋友,就只需要在页面相应地方里面写一句:
<friend description="描述" url="网址">朋友的名字</friend>
  1. Vice versa,如果我们需要修改卡片的样式,我们只需要修改组件的 template 里面的代码(当然你可以进一步将 CSS 分离出来)。

  2. 本方法用的是 Vue 组件,它不会与原有的 Vue App 冲突(不过组件必须要写在 Vue App 里面。)

参考

如果你对上文所说内容仍有疑惑,可以翻看下面的链接。

Bootstrap 4 卡片 菜鸟教程

Vue - 模板语法 和 Attribute

Vue - 组件模板中插槽的使用

Vue - 组件的 props 属性

后记

复制粘贴永远都是愚蠢的做法,而反人类的设计早有一日会被崭新的设计替代。

How can we do better?

这句话是 Robert Sedgewick 老先生在算法公开课里面经常提到的。只有不断思考How can we do better,认知才会不断提高。否则对着一个愚蠢的做法沾沾自喜,永远不会有进步。

另外有问题的话,欢迎在评论区交流。


Last modified on 2020-03-16