在掌握了如何构建与编译 Vue 组件的基础知识之后,接下来就可以试着来构建一些更具有实际用处的复杂组件了。为了赋予组件更具实用性的后面,首先要做的就是让这些组件具备监听用户自定义事件的能力,并且允许用户为这些自定义事件注册相应的处理函数,而这一切都要从v-on指令在 Vue 组件中的使用说起。

组件中的v-on指令

接下来,我将会通过记录为之前的say-hello组件增加一个名为"show-message"的自定义事件,并为该事件注册处理函数的过程来学习如何赋予 Vue 组件事件处理能力。首先,我会暂且假设<say-hello>标签所对应的组件已经在监听一个名为"show-message"的自定义事件,并在index.htm中使用v-on指令为其指定了事件处理函数,具体代码如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>学习 vue 组件实验(3):以专用文件格式注册组件</title>
</head>
<body>
<div id="app">
<say-hello @show-message="showMessage"
:who="who">
</say-hello>
</div>
</body>
</html>

然后,我只需要和之前使用 HTML 标准标签元素一样,在main.js中与上述页面对应的 Vue 实例中添加"show-message"事件处理函数的实现,具体代码如下:

import Vue from 'vue';
import sayHello from './sayHello.vue'; new Vue({
el: '#app',
components: {
'say-hello': sayHello
},
data: {
who:'vue'
},
methods: {
showMessage : function() {
window.alert('Hello, ' + this.who);
}
}
});

到目前为止,大家所看到的步骤与普通的事件处理过程并没有什么区别,接下来我只需要让之前做的假设成真就可以了。换而言之,现在的任务是要真正实现让<say-hello>组件监听"show-message"这个自定义事件。对于此类问题,Vue.js 框架为我们提供的解决方案是:利用组件内部的某个 HTML 元素标签的标准事件来触发该组件的自定义事件。具体到当前项目中,我要做的就是对sayHello.vue文件做出如下修改:

<template>
<div class="box">
<h1>你好, {{ you }}!</h1>
<input type="text" v-model="you" />
<input type="button" value="弹出对话框" @click="showMessage">
</div>
</template> <script>
const sayHello = {
name: 'sayHello',
props : ['who'],
data : function() {
return {
you: this.who
}
},
methods: {
showMessage: function() {
this.$emit('show-message', this.who);
}
}
};
export default sayHello;
</script> <style scoped>
.box {
height: 130px;
width: 250px;
background-color: #ccc;
}
</style>

在上述代码中,我首先在组件template模版部分中添加了一个显示文本为"弹出对话框"的按钮元素,并为其注册了单击事件的处理函数。然后在实现该单击事件的处理函数时,我通过调用this.$emit()方法通知了当前组件的调用方(即index.htm页面):"show-message"事件被触发了。在这里,this.$emit()方法的第一个实参应该是一个用于指定该组件被触发的事件名称。尔后,如果还有要传递给该组件事件处理函数的实参,还可以在后面依次加上这些实参(例如这里的this.who)。这样一来,<say-hello>标签的用户只需要单击该组件中的"弹出对话框"按钮,就可以触发"show-message"事件了。

组件中的v-model指令

当然,和普通的 HTML 元素标签一样,使用v-on指令绑定事件的方法只能处理一些简单的操作,对于更为复杂的表单操作,还是需要用到v-model指令来实现。下面,我将通过记录实现一个"计数器"组件的过程来了解v-model指令在 Vue 组件中的使用方法。为此,我们需要开启第四个实验项目,其具体构建步骤如下:

  1. 配置项目并安装依赖项

    首先,我需要在code/00_test目录中再创建一个名为component_4的实验目录。然后,由于component_4项目所需要的依赖项以及姜母结构都与component_3项目相同,为了免除不必要的工作量,以节省花费项目配置上的时间,我们可以直接将component_3目录下的package.jsonwebpack.config.js这两个项目配置文件拷贝至component_4目录下(如果需要的话,也可以稍作修改),并在component_4目录下执行npm install命令来安装已经配置在package.json文件中的项目依赖项。

  2. 假设组件已支持v-model指令

    与之前一样,我可以暂且假设自己手里已经有了一个支持v-model指令的"计数器"组件,并在项目的src/main.js中实现 Vue 实例时将其注册成了局部组件,具体代码如下:

     import Vue from 'vue';
    import counter from './counter.vue'; new Vue({
    el: '#app',
    components: {
    'my-counter': counter
    },
    data: {
    num: 0
    },
    methods: {}
    });

    然后,我只需在src/index.htm文件中像使用普通的 HTML 元素标签一样,对其使用v-model指令即可,具体代码如下:

     <!DOCTYPE html>
    <html lang="zh-cn">
    <head>
    <meta charset="UTF-8">
    <title>学习 vue 组件实验(4):构建更复杂的组件</title>
    </head>
    <body>
    <div id="app">
    <my-counter v-model="num"></my-counter>
    </div>
    </body>
    </html>
  3. 实现组件对v-model指令的支持

    现在的任务就是实现这个"计数器"并让其以符合之前假设的方式支持v-model指令。在此之前我们首先知道,在 Vue.js 框架的组件语义下,v-model指令本质上只是一个语法糖。换而言之,<my-counter v-model="num"></my-counter>实际上等价于:

    <my-counter :value="num" @input="num = $event.target.value"></my-counter>

    所以,我们在src/counter.vue文件中实现"计数器"组件时只需要按照之前学习到的方法分别处理一下由v-bind指令绑定的value组件属性和由v-on指令注册的input自定义事件即可,具体代码如下:

     <template>
    <div class="box">
    <input type="button" value="-" @click="changeCounter(-1)">
    <input type="text" :value="value" @input="changeInput" >
    <input type="button" value="+" @click="changeCounter(1)">
    </div>
    </template> <script>
    const counter = {
    name: 'counter',
    props : ['value'],
    methods: {
    changeCounter: function(count) {
    this.$emit('input', this.value + count);
    },
    changeInput: function(event) {
    let num = parseInt(event.target.value);
    if(isNaN(num)) {
    num = 0;
    }
    this.$emit('input', num);
    }
    }
    };
    export default counter;
    </script> <style scoped>
    .box {
    width: 340px;
    padding: 5px;
    background-color: #ccc;
    }
    </style>

组件插槽

到目前为止,大家看到的都是一些功能单一的组件,但在实际生产环境中,我们在很多时候可能需要将这些功能单一的组件组合成一个更为复杂的组件,这意味着我们需要像使用普通 HTML 元素标签一样嵌套使用组件的自定义标签,例如在下面这段 HTML 代码中:

<div>
<h1>标题</h1>
</div>

<h1>标签是被插入到<div>标签的内部的,要想在 Vue 组件的自定义标签中实现这样的效果,就必须要预先在用作外层标签的组件模版中预留一些插槽标签(即<slot>),以指定内层标签可以插入的位置。例如,我可以执行一下步骤来为上面的"计数器"组件增加一个外层盒子,以便用户可以为自己的计数器增加一个标题:

首先,在component_4/src目录下创建一个名为box.vue文件,并在其中编写如下代码:

<template>
<div>
<header>
<slot name="title"></slot>
</header>
<main>
<slot></slot>
</main>
</div>
</template> <script>
const box = {
name: 'box'
};
export default box;
</script> <style scoped>
</style>

然后在使用该组件之前,我同样需要先在component_4/src/main.js文件中将其注册为 Vue 实例的局部组件,具体代码如下:

import Vue from 'vue';
import box from './box.vue'
import counter from './counter.vue'; new Vue({
el: '#app',
components: {
'my-box' : box,
'my-counter': counter
},
data: {
num: 0
},
methods: {}
});

现在,我们就可以在component_4/src/index.htm文件中嵌套使用组件的标签了。正如大家所见,我在box组件中为用户预留了两种最常用的插槽,一种是带name 属性的<slot>标签,通常被称之为"具名插槽";另一种是不带属性的<slot>标签,通常被称之为"默认插槽"。其中,具名插槽的作用是指定待插入元素的意义或功能,需用带v-slot指令的<template>标签来指定,而默认插槽实际上就是名称为default的插槽。在这里,所有被插入到box组件标签内部,且没有被<template>标签指定的元素标签都会被插入到该插槽中。例如,我们可以像下面这样为box组件插入内容:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>学习 vue 组件实验(4):构建更复杂的组件</title>
</head>
<body>
<div id="app">
<my-box>
<template v-slot:title>
<h1>我的计数器</h1>
</template>
<p>这是一个"计数器"组件:</p>
<my-counter v-model="num"></my-counter>
</my-box>
</div>
</body>
</html>

当然,如果想要让 HTML 文档的结构更清晰一些,我们也可以使用带v-slot指令的<template>标签来指定要插入到默认插槽中的内容,具体做法如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>学习 vue 组件实验(4):构建更复杂的组件</title>
</head>
<body>
<div id="app">
<my-box>
<template v-slot:title>
<h1>我的计数器</h1>
</template>
<template v-slot:default>
<p>这是一个"计数器"组件:</p>
<my-counter v-model="num"></my-counter>
</template>
</my-box>
</div>
</body>
</html>

Vue.js 学习笔记之六:构建更复杂的组件的更多相关文章

  1. Vue.js学习笔记(2)vue-router

    vue中vue-router的使用:

  2. vue.js 学习笔记3——TypeScript

    目录 vue.js 学习笔记3--TypeScript 工具 基础类型 数组 元组 枚举 字面量 接口 类类型 类类型要素 函数 函数参数 this对象和类型 重载 迭代器 Symbol.iterat ...

  3. Vue.js学习笔记:在元素 和 template 中使用 v-if 指令

    f 指令 语法比较简单,直接上代码: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" " ...

  4. vue.js学习笔记(一)——vue-cli项目的目录结构

    vue.js是一套构建用户界面的渐进式框架.vue采用自底向上增量开发的设计.vue的核心库只关心视图层,非常容易学习,非常容易与其它库和已有项目整合.vue完全有能力驱动采用单文件组件和vue生态系 ...

  5. Vue.js 学习笔记之七:使用现有组件

    5.3 使用现有组件 在之前的五个实验中,我们所演示的基本都是如何构建自定义组件的方法,但在具体开发实践中,并非项目中所有的组件都是需要程序员们自己动手来创建的.毕竟在程序设计领域,"不要重 ...

  6. Vue.js学习笔记(介绍)

    Vue语法也可以进行APP开发,需要借助weex Vue.js是一套构建用户界面的框架,只关注视图层,便于与第三方库或既有项目整合. 在Vue中的核心概念:让用户不能操作Dom元素(减少不必要的dom ...

  7. Vue.js——学习笔记(一)

    Vue-自学笔记 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅 ...

  8. Vue.js 学习笔记之五:编译 vue 组件

    正如上一篇笔记中所说,直接使用 ES6 标准提供的模块规范来编写 Vue 组件在很多情况下可能并不是最佳实践.主要原因有两个,首先是市面上还有许多并没有对 ES6 标准提供完全支持的 Web 浏览器, ...

  9. Vue.js——学习笔记

    Vue-自学笔记 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅 ...

随机推荐

  1. Volatile禁止指令重排序(三)

    Volatile禁止指令重排 计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令重排,一般分为以下三种: 源代码 -> 编译器优化的重排 -> 指令并行的重排 -> 内存系 ...

  2. Shell学习(三)Shell参数传递

    一.传参实例 ##脚本文件内容 #执行的文件名 echo $0; #第一个参数 echo $1; #第二个参数 echo $2; #第三个参数 echo $3; ##调用语句 ./testShell. ...

  3. Asp.Net Core Log4Net 配置分多个文件记录日志(不同日志级别)

    本文所有配置都是在core3.1环境下. 首先看看最终的效果. 请求监控:对每次请求的相关信息做一个记录. 全局异常:我不想我的错误信息,跟其他的信息混合在一起,查看的时候不大方便. 应用日志:这个主 ...

  4. Java中synchronized关键字理解

    好记性不如烂笔头~~ 并发编程中synchronized关键字的地位很重要,很多人都称它为重量级锁.利用synchronized实现同步的基础:Java中每一个对象都可以作为锁.具体表现为以下三种形式 ...

  5. 手把手教你springboot中导出数据到excel中

    手把手教你springboot中导出数据到excel中 问题来源: 前一段时间公司的项目有个导出数据的需求,要求能够实现全部导出也可以多选批量导出(虽然不是我负责的,我自己研究了研究),我们的项目是x ...

  6. Python-临时文件文件模块-tempfile

    案例: 某项目中,从传感器中获得采集数据,每收集到1G的数据后做是数据分析,最终只保留数据分析的结果,收集到的数据放在内存中,将会消耗大量内存,我们希望把这些数据放到一个临时的文件中 临时文件不能命名 ...

  7. (leetcode每日打卡)秋叶收藏集【动态规划】

    LCP 19.秋叶收藏集 题目链接 算法 动态规划 时间复杂度O(n) 1.题目要求最终形成[红.黄.红]三部分,每部分数量可以不相等,问最终调整操作数量最小是多少.这道题一开始考虑暴力去做,枚举两个 ...

  8. RT Thread的SPI设备驱动框架的使用以及内部机制分析

    注释:这是19年初的博客,写得很一般,理解不到位也不全面.19年末得空时又重新看了RTThread的SPI和GPIO,这次理解得比较深刻.有时间时再整理上传. -------------------- ...

  9. 解决Dubbo无法发布被事务代理的Service问题

    在HelloServiceImpl类上加入@Transactional注解后,虽然工程可以正常跑起来,但是通过dubbo管理控制台可以看到里面并没有服务发布上来. 此时启动服务提供者和服务消费者,并访 ...

  10. Python3基础——字符串类型

    Text Sequence Type - str(immutable) class str(object='') class str(object=b'', encoding='utf-8', err ...