2.1 简单轮子VueInput.vue:文本输入框 和单元测试
大纲链接 §
[toc]
VueInput
组件需求分析
User Case
- 输入
- 提示 用户名必须为英文
- 报错信息
- 清空
- 复制/粘贴
- 键盘
Tab
- 敲击回车
- 不可输入
输入框状态 11 种
enable
默认状态hover
状态 (移动端无)focus
状态error
状态 (危险色提示文字)error hover
状态 (移动端无)error focus
状态
sucess
状态 (原谅色提示文字)sucess hover
状态 (移动端无)sucess focus
状态
disable
状态readonly
状态
lable
名称 + 提示文字 / + 按钮
lable
名称 的 位置lable
在上方lable
在左方
- 提示图标 + 提示文字
- 提示图标 叹号
- 提示文字 颜色跟随图标
- 提示信息
- 用户名
- 已被占用
- 错误
- 不存在
- 密码
- 太短
- 错误
- 提示信息位置
- 右方
- 下方
- 用户名
- 按钮
- 输入框 + 搜索按钮(右侧)
- 名称按钮(左侧) + 输入框
- 默认占位提示
placeholder
API设计
写 VueInput
组件
新建
./src/components/input/VueInput.vue
|
|
- 样式标签中加
scoped
属性,在生成的相同组件中的标签样式使用同一个data-v-xxxxx
作为唯一id,隔绝同名样式
增加 error
状态
VueInput.vue
|
|
:class="{..., 'error': error}">
可以简写为:class="{..., error}">
使用<template></template>
配合v-if
包裹临时标签组
- 不恰当的写法:
|
|
- 更好的写法:
|
|
<template></template>
会编译后自动消失,不用添加额外的标签和样式- 缺点也是当需要特别的样式时,在
<template></template>
上添加样式无效
input
的 change
事件
<VueInput></VueInput>
上添加监听事件@change.native="xxx"
- 或者在
VueInput.vue
里的<input>
标签上监听@change="xxx"
VueInput.vue
|
|
- 向父组件传递自定义事件
change($event: { target: HTMLInputElement }) {this.$emit('updateChange', $event.target.value);}
- 使用解构赋值
$event: { target: HTMLInputElement }
定义形参类型 - 发布的自定义事件可以传第三个参数
this.$emit('updateChange', $event.target.value , 'Hi');
Inputs.vue
中回调函数接受参数,使用inputChange(xxx, yyy) {console.log(yyy)}
的第二个形参接受yyy
的值即'Hi'
Inputs.vue
|
|
测试驱动开发
测试外部属性props
input.test.ts
|
|
- 每次的重复代码太多
- 将测试用例中的重复代码提取到
Mocha.js Hooks
的生命周期函数中 - 使用每次运行测试前后的钩子函数
beforeEach
afterEach
重构input.test.ts
|
|
- 作用域被隔开了,
vm
的作用域分别在各自的测试用例中 - 在外部统一提前声明
const Constructor = Vue.extend(VueInput);
let vm: Vue;
测试事件
测试 change
事件
|
|
- 如何手动触发事件
- 搜
trigger change event manually
- 搜
|
|
- 使用
new Event('change')
API 创建事件 - 使用
inputElement.dispatchEvent(new Event('change'));
API 触发事件 - 控制台打印出
changeEvent
- 发现
Event{isTrusted: false}
注意属性{isTrusted: false}
- 事件不是浏览器响应UI产生的
- 发现
- 控制台打印出
inputElement
<input data-v-f67744="" type="text" class="">
测试
change
事件失败
- 因为
VueInput
组件传递给外部父组件的是自定义事件updateChange
this.$emit('updateChange', $event.target.value);
- 改为传
change
事件this.$emit('change', $event.target.value);
- 再次测试
change
事件
手动触发的
change
能否正确地传递事件的参数
- 先将子组件
VueInput.vue
触发input
事件时发布的自定义事件改为this.$emit('change', $event);
测试 Inputs.vue
事件
|
|
- 对比浏览器触发的和使用 API 代码触发的
change
事件- 用户操作UI产生的
Event {isTrusted: true...}
- 调用
API
产生的Event {isTrusted: false...}
- 其他属性都相同
- 用户操作UI产生的
- 可以模拟
还期待
spy
函数在触发(called
)的时候传递参数Event
- 查看
sinon-chai
文档 - 使用
expect(callback).to.have.been.calledWith(event)
input.test.ts
|
|
测试 VueInput.vue
的其他事件
input
事件focus
事件blur
事件
input.test.ts
|
|
- 重复代码太多
- 重构
input.test.ts
|
|
- TDD 测试代码全部通过,即开发完毕
目前的
VueInput
只支持传参和事件
让 VueInput
支持 v-model
(模拟双向绑定)
双向绑定
- 用户的操作(输入)可改变数据(绑定到JS中的变量)
- JS代码逻辑改变数据
Vue 使用 v-model
模拟双向绑定
|
|
其实
v-model
只是语法糖,相当于以下代码
|
|
<input>
中的v-model
相当于:- 绑定属性
:value="message"
- 监听
input
事件,并且赋给事件目标的值@input="message = $event.target.value"
- 绑定属性
参考 demo
VueInput
实现支持 v-model
修改
VueInput
中的事件传值$event.target.value
|
|
Inpus.vue
已经实现了v-model
|
|
v-model
实现了
- 绑定数据
message
- 监听
input
事件,响应触发,改变数据message
测试v-model
测试挂了
- 因为之前测试传的是事件
expect(callback).to.have.been.calledWith(triggerEvent);
- 现在传的是事件目标的值
$event.target.value
,未得到完整的事件对象,未调用calledWith(triggerEvent)
控制台打出
console.log('triggerEvent: ', triggerEvent);
|
|
- 得到
Event{isTrusted: false}
,只有isTrusted: false
这一个属性,没有value
属性
value = 'hi'
赋值? 期待参数calledWith('hi')
event.target = { value: 'hi' }
- 期待参数
expect(callback).to.have.been.calledWith('hi');
- 报错,显示
cannot assign read only property 'target' of object '#<Event>'
是只读属性 - 只能在事件上添加指定的属性
new Event("change", {"bubbles": true, "canclable": false, "composed": true})
是否冒泡 是否可取消 是否合成
搜索
js new event set target property
- stackoverflow How to set target property when simulating mouseclick in javascript?
- stackoverflow How set the EventTarget of an Event
使用Object.defineProperty
添加事件对象的属性
Object.defineProperty( triggerEvent, 'target', {value: {value: 'hi'}} );
input.test.ts
|
|
其他注意
VueButton.vue
注意其中的<button></button>
元素必须设置属性type="button"
- 按钮不是用于向服务器提交数据,请确保这些按钮的 type 属性设置成 button
- 否则它们被按下后将会向服务器发送数据并加载(可能并不存在的)响应内容
- 因而可能会破坏当前文档的状态,比如在 url 后添加
?
,路由跳转 - 详见 MDN
VueInput
简单轮子:文本输入框小结
- 测试驱动开发
karma
提供运行器,打开ChromeHeadless
karma
打开测试文件dist/**/*.test.js
dist/**/*.test.css
karma
测试结果信息[progress]
karma
引入mocha
mocha
提供describe
方法mocha
提供it
方法- 全局属性,无需手动引入
karma
引入sinon-chai
sinon-chai
提供fake
方法sinon-chai
提供expect
方法sinon-chai
提供called
方法sinon-chai
提供calledWith
方法
- ``提供
describe
方法
其他
安装浏览器插件
vue
开发者工具
- 组件属性
name
的用途:进行组件标签的命名
参考文章
相关文章
- 无
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名
- 河 掘 思 知 简