写点什么

3 个概念,入门 Vue 组件开发

  • 2019-04-01
  • 本文字数:6007 字

    阅读完需:约 20 分钟

3个概念,入门 Vue 组件开发

“组件”是 Vue 中比较基础的概念,但我发现,许多同学对 Vue 组件的概念和由来并不是清楚。因此,我希望通过这个专题,带大家换个角度来分析,最终让大家更清楚组件开发。


首先,我们先不谈组件,我想问大家一个问题:


我们平常用任何编程语言写方法(method)的时候,当一个方法里的逻辑过多时,我们会怎么办?当多个方法里有很多相似的逻辑时,我们该怎么办?


答案很明了:拆分成一个独立的方法。


如果拆分后还是有类似问题呢?那就继续拆分。


类比一下,HTML 也一样。当我们写了一大堆的 HTML 后,发现有不少类似或重复的地方,我们也可以按照拆分的方法,拆分 HTML。除了拆分 HTML 之外,我们还可以拆分针对这段 HTML 书写的逻辑,甚至是样式。拆分后的 HTML,逻辑,样式组合在一起,我们就称之为组件。


这么讲似乎有点抽象,我们来举个例子吧。假如我们要做一个简单的 TodoList 项目,代码如下:


<ul>​    <li>​      <input type="checkbox">​      <span>学习 Vue 属性</span>​      <button>删除</button>​    </li>​    <li>​      <input type="checkbox">​      <span>学习 Vue 事件</span>​      <button>删除</button>​    </li>​    <li>​      <input type="checkbox">​      <span>学习 Vue 插槽</span>​      <button>删除</button>​    </li>  </ul></div>
复制代码


可以看到,我们 li 标签内的内容越来越多,似乎可以把它独立出来,在 Vue 中,通过以下代码就可以将这部分代码独立出来.


通过 Vue.component 定义(注册)一个组件,起名为 todo-item, 组件的 HTML 写在 template 字段上:


Vue.component('todo-item', {  template: `<li>​      <input type="checkbox">​      <span>学习 Vue 属性</span>​      <button>删除</button>​    </li>`})
复制代码


然后,你可以通过下面这样的方式来使用这个组件:


  <ul>​    <todo-item></todo-item>​    <todo-item></todo-item>​    <todo-item></todo-item>  </ul></div>
复制代码


当然前提条件是你要先 new Vue 一个实例,并添加挂载点


new Vue({  el: '#app'  // 提供一个挂载点,这样我们就可以在里面使用 todo-item 了})
复制代码


这样一来清爽了许多,可是这样就变成三个“学习 Vue 属性” 事项了,我们还缺“学习 Vue 事件”和“学习 Vue 插槽” ,怎么办呢,这就要用到 Vue 的属性了。


点击此处,开始你的第一个 Vue 程序


点击此处,了解单文件组件

属性

我们接着改改,调用方法时,可以传递不同的参数,方法也可以接收参数,执行不同的逻辑,加载组件时同样也可以传递不同的参数(属性),组件也可以接收参数(属性)来显示不同的内容:


Vue.component('todo-item', {  props: ['item'], // 声明能接收的参(属)数(性)  // {{item}} 使用传递过来的 item  template: `<li>​      <input type="checkbox">​      <span>{{item}}</span>​      <button>删除</button>​    </li>`})
<div id="app"> <ul>​ <todo-item item="学习 Vue 属性"></todo-item>​ <todo-item item="学习 Vue 事件"></todo-item>​ <todo-item item="学习 Vue 插槽"></todo-item> </ul></div>
复制代码


我们再精简一下:


 <ul>​    <todo-item v-for="item in list" :item="item"></todo-item>  </ul></div>new Vue({  el: '#app',  data() {​    return {​      list: ['学习 Vue 属性', '学习 Vue 事件', '学习 Vue 插槽']​    }  }})
复制代码


这样就可以了,是不是很简单?


点击此处,深入学习 Vue 中组件的属性

事件

我现在已经学完了 Vue 属性,想要从 todolist 里面把它删除掉,这好像并不太容易。这时,我需要给 button 绑定一个事件,当然 Vue 提供给我们了一个简单的方式进行绑定事件,用@xxx 就可以进行事件绑定了(这里的 xxx 指的任一字符串,根据你的实际需要来命名就行)


Vue.component('todo-item', {  props: ['item'],  template: `<li>​      <input type="checkbox">​      <span>{{item}}</span>​      <button @click="handleClick">删除</button>​    </li>`,  methods: {​    handleClick() {​    }  }})
复制代码


然后我们需要把点击事件告诉我们的上层(父组件),Vue 同样给我们提供了一个 API:this.$emit(‘xxx’, …),我们既然是做删除操作,那就是叫 delete 好了,我们还可以传递更多的参数,如 this.item:


handleClick() {  this.$emit('delete', this.item)}
复制代码


上层组件还缺少了一个用来接收 delete 的地方,我们可以通过 @delete 的方式来绑定一个用来接收 delete 事件的方法:


<todo-item v-for=“item in list” :item=“item” @delete=“handleDelete”>


最后只需要在 methods 字段上定义一个 handleDelete 方法,改变 list 数组就完成了我们的删除操作:


new Vue({  el: '#app',  data() {    return {      list: ['学习 Vue 属性', '学习 Vue 事件', '学习 Vue 插槽']    }  },  methods: {    handleDelete(item) {      const index = this.list.findIndex(text=>text === item);      this.list.splice(index, 1);    }  }})
复制代码


以上就是 Vue 中事件的用法。


点击此处,深入学习 Vue 中组件的事件

插槽

现在我想让这个 TodoList 中的“学习 Vue XXX”前加个图标 Icon,怎么办呢?还好 Vue 早就帮我想到了,我们不能再通过属性传递这些带有标签的内容,而是通过一种名叫“插槽”的东西进行传递:


<todo-item v-for="item in list" :item="item" @delete="handleDelete">  <span>我是Icon</span></todo-item>
复制代码


当然我们也不能再用双括号来解析,我们需要使用这种写法来解析:


template: `<li>​      <input type="checkbox">​      <span>{{item}}</span>​      <slot></slot>​      <button @click="handleClick">删除</button>​    </li>`,
复制代码


这种我们称之为默认插槽。


现在我想更进一步,添加两个图标,一个在文字前面,一个在文字后面,没问题:


<todo-item v-for="item in list" :item="item" @delete="handleDelete">  <span slot="prefixIcon">我是前缀Icon</span>  <span slot="suffixIcon">我是后缀Icon</span></todo-item>
复制代码


同样 template 需要更改:


template: `<li>​      <input type="checkbox">​      <slot name="prefixIcon"></slot>​      <span>{{item}}</span>​      <slot name="suffixIcon"></slot>​      <button @click="handleClick">删除</button>​    </li>`,
复制代码


这便是我们的具名插槽。


如果想让功能更加丰富的话,比如我想根据我的 input checkbox 的是否选中来改变图标的颜色,该怎么做?


第一步,记录我们 input 的选中状态,我们使用 Vue 的 v-model 进行 input 的双向绑定:


Vue.component('todo-item', {  props: ['item'],  data() {​    return {​      checked: false, // 默认不选中​    }  },  template: `<li>​      <input type="checkbox" v-model="checked">​      <slot name="prefixIcon"></slot>​      <span>{{item}}</span>​      <slot name="suffixIcon"></slot>​      <button @click="handleClick">删除</button>​    </li>`,  methods: {​    handleClick() {​      this.$emit('delete', this.item)​    }  }})
复制代码


状态有了,现在需要把这个状态传递给上层:


<slot name="prefixIcon" v-bind="{checked}">我是前缀Icon</slot>
复制代码


接收到状态后并根据状态提供不同颜色的图标:


<span slot="prefixIcon" slot-scope="props" :style="{color: props.checked ?'red':'blue'}">我是前缀Icon</span>
复制代码


这就是我们的作用域插槽。


为了方便理解,插槽使用方式我们使用了 Vue 2.5 版本的语法进行讲解,Vue 2.6 的语法可查看视频教程。


点击此处,深入学习 Vue 中组件的插槽


如果你已经阅读到了这里,那么恭喜你,你已经可以进行简单的 Vue 组件开发了。


如果还想学习更多的 Vue 实战技巧,欢迎订阅我的视频课程《Vue 开发实战》


2019-04-01 17:443977

评论 1 条评论

发布
用户头像
<span slot="prefixIcon" slot-scope="props" :style="{color: props.checked ?'red':'blue'}"> 我是前缀 Icon</span>
这行代码里面 slot-scope="props" 是什么意思呢?
2019-04-10 14:34
回复
没有更多了
发现更多内容

合合信息加入元脑生态 携手浪潮信息推动金融AI应用创新

合合技术团队

AI 智能时代 合合信息 人工智能’ 浪潮

计算机专业和培训出来的前端程序员的区别

小谷哥

博云入选国家级专精特新「小巨人」名单!

BoCloud博云

云计算 容器 “小巨人”企业

开源图编辑库 NebulaGraph VEditor 的设计思路分享

NebulaGraph

数据库 图数据库 知识图谱 NebulaGraph

大数据程序员参加培训好还是自学好

小谷哥

终于!极狐GitLab 支持 ARM 啦!

极狐GitLab

DevOps 敏捷开发 arm 极狐GitLab 嵌入式硬件

迄今为止把Mybatis讲解的最详细的PDF,图文并茂,通俗易懂

冉然学Java

Java 编程 程序员 mybatis 构架

2022年中国足球赛事营销洞察

易观分析

营销 报告 足球

秒云获得阿里云首批产品生态集成认证,携手共建云原生智能运维生态服务

MIAOYUN

智能运维 智能运维AIOps 阿里云产品生态集成认证

破解双中台困局:万家数科 x StarRocks 数字化技术实践

StarRocks

大数据

数据说|数字经济,山东16市谁最“炫”?排行榜来了

易观分析

数字经济 山东

过等保费用包含哪些?大概多少钱?

行云管家

等保 等级保护 过等保

Alluxio on Amazon EMR 集成实践

亚马逊云科技 (Amazon Web Services)

实践 集成 Tech 专栏

java就业培训班如何选择?

小谷哥

前端培训学完课程后如何找工作?

小谷哥

二分查找:一种效率较高的查找方法

华为云开发者联盟

开发 二分查找 查找 区间

表达式转换-中缀转后缀表达式后计算-数据结构与算法

清风莫追

算法与数据结构 8月月更

开源一夏 | TypeScript对于Duck类型和模块命名空间的应用实战

恒山其若陋兮

开源 8月月更

史上最全的Java并发系列之Java并发容器和框架

自然

多线程 并发 8月月更

史上最全的Java并发系列之Java并发机制的底层实现原理

自然

多线程 并发 8月月更

预约直播 | 深度学习编译器技术趋势与阿里云BladeDISC的编译器实践

阿里云大数据AI技术

深度学习 阿里云 编译器

IPv5是什么意思?到底有没有IPv5?

郑州埃文科技

ipv6 互联网协议 ipv5

开源公开课丨ChunJun数据传输模块介绍

袋鼠云数栈

史上最全的Java并发系列之并发编程的挑战

自然

多线程 并发 8月月更

这次6张图带你彻底搞懂RocketMQ是怎么保存偏移量的?

程序员小毕

Java 程序员 面试 RocketMQ 消息中间件

旺链科技成为湖南省区块链协会理事单位

旺链科技

区块链 区块链技术 产业区块链

大数据培训学习软件工程师机构靠谱吗

小谷哥

Go-Excelize API源码阅读(十)—— SetActiveSheet(index int)

Regan Yue

Go 开源 源码阅读 8月日更 8月月更

CSO视角:Sigstore如何保障软件供应链安全?

SEAL安全

软件供应链安全 OpenSSF

【云原生】Docker 进阶 -- 数据卷使用与实战练习

Bug终结者

Docker 阿里云 云原生 8月月更

面试的朋友听我说,18个MyBatis高频知识及学习笔记,双手奉上

冉然学Java

Java 源码 分布式 mybatis 构架

3个概念,入门 Vue 组件开发_大前端_唐金州_InfoQ精选文章