详解Angular中实现自定义组件的双向绑定的两种方法


Posted in Javascript onNovember 23, 2018

在 Angular 中,对于表单元素,通过 [(ngModel)] 即可以简单地实现双向绑定。对于自定义组件而言,希望实现同样的效果可以怎么做呢?

1 实现自定义组件的 ngModel 指令

如果希望自定义组件能够具有与表单元素相同的 ngModel 效果,可以通过在组件内实现 ControlValueAccessor 接口达到目的。

对于 [(ngModel)] ,需要至少实现该接口的如下方法:

interface ControlValueAccessor { 
 writeValue(obj: any): void
 registerOnChange(fn: any): void
 registerOnTouched(fn: any): void
}

最简单的核心实现示例参考如下。

import { ControlValueAccessor } from '@angular/forms/src/directives';
import { Component, forwardRef, Input } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
 selector: 'custom-input',
 template: `<input [(ngModel)]="value"/>`,
 providers: [
  {
   provide: NG_VALUE_ACCESSOR,
   useExisting: forwardRef(() => UnionInputComponent),
   multi: true
  }
 ]
})
export class CustomInputComponent implements ControlValueAccessor {
 constructor() { }
 private innerValue: any = '';
 private onTouchedCallback: () => void = function () { };
 private onChangeCallback: (_: any) => void = function () { };

 get value(): any {
  return this.innerValue;
 }
 set value(v: any) {
  if (v !== this.innerValue) {
   this.innerValue = v;
   this.onChangeCallback(v);
  }
 }
 /**
  * model view -> view value
  */
 writeValue(value: any) {
  if (value !== this.innerValue) {
   this.innerValue = value;
  }
 }
 /**
  * view value ->model value
  */
 registerOnChange(fn: any) {
  this.onChangeCallback = fn;
 }
 registerOnTouched(fn: any) {
  this.onTouchedCallback = fn;
 }
}

2 使用 get/set 关键字实现父子组件的双向绑定

其实实现双向绑定内部的本质原理就是父子组件的事件绑定机制。简单举例如下。

2.1 自定义子组件定义

import { Input, Output, Component, EventEmitter } from '@angular/core';

@Component({
 selector: 'custom-input',
 template: `<input [(ngModel)]="innerValue"/>`,
})
export class CustomInputComponent {
 innerValue;

 @Input()
 get twoWayModel() {
  return this.innerValue;
 }
 set twoWayModel(val) {
  this.innerValue = val;
  this.twoWayModelChange.emit(this.innerValue);
 }
 @Output() twoWayModelChange: EventEmitter<string> = new EventEmitter</string><string>();
}

2.2 使用自定义组件

在需要使用组件的地方,通过 [(twoWayModel)] 即可实现双向绑定的效果。

import { Input, Output } from '@angular/core';
import { Component, forwardRef, Input } from '@angular/core';
@Component({
 selector: 'custom-input',
 template: `<custom -input [(twoWayModel)]="inputValue" (twoWayModelChange)="onInputValueChange($event)"></custom>`
})
export class abcComponent {
 inputValue;
 onInputValueChange(val) {
  console.log(val);
  console.log(val === this.inputValue); // true
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
很可爱的输入框
Aug 03 Javascript
动态改变div的z-index属性的简单实例
Aug 08 Javascript
Javascript 颜色渐变效果的实现代码
Oct 01 Javascript
Jqgrid表格随窗口大小改变而改变的简单实例
Dec 28 Javascript
node.js中的fs.existsSync方法使用说明
Dec 17 Javascript
jQuery中end()方法用法实例
Jan 08 Javascript
javascript瀑布流式图片懒加载实例解析与优化
Feb 23 Javascript
浅析javascript中的Event事件
Dec 09 Javascript
几个你不知道的技巧助你写出更优雅的vue.js代码
Jun 11 Javascript
小程序云开发教程如何使用云函数实现点赞功能
May 18 Javascript
Vue Router 实现动态路由和常见问题及解决方法
Mar 06 Javascript
js实现网页随机验证码
Oct 19 Javascript
Vue.js组件间通信方式总结【推荐】
Nov 23 #Javascript
vue-cli 2.*中导入公共less文件的方法步骤
Nov 22 #Javascript
vue全局使用axios的方法实例详解
Nov 22 #Javascript
vue中的ref和$refs的使用
Nov 22 #Javascript
浅析vue 函数配置项watch及函数 $watch 源码分享
Nov 22 #Javascript
原生JS实现手动轮播图效果实例代码
Nov 22 #Javascript
js实现按钮开关单机下拉菜单效果
Nov 22 #Javascript
You might like
收藏的一个php小偷的核心程序
2007/04/09 PHP
php的debug相关函数用法示例
2016/07/11 PHP
A标签中通过href和onclick传递的this对象实现思路
2013/04/19 Javascript
JS格式化数字金额用逗号隔开保留两位小数
2013/10/18 Javascript
jquery自动切换tabs选项卡的具体实现
2013/12/24 Javascript
LABjs、RequireJS、SeaJS的区别
2014/03/04 Javascript
js如何调用qq互联api实现第三方登录
2014/03/28 Javascript
跟我学习javascript的prototype,getPrototypeOf和__proto__
2015/11/17 Javascript
js文本框输入内容智能提示效果
2015/12/02 Javascript
详解页面滚动值scrollTop在FireFox与Chrome浏览器间的兼容问题
2015/12/03 Javascript
详解js中构造流程图的核心技术JsPlumb(2)
2015/12/08 Javascript
基于jquery实现瀑布流布局
2020/06/28 Javascript
jQuery+Ajax实现无刷新操作
2016/01/04 Javascript
老生常谈 关于JavaScript的类的继承
2016/06/24 Javascript
jQuery表单元素选择器代码实例
2017/02/06 Javascript
如何重置vue打印变量的显示方式
2017/12/06 Javascript
JS从非数组对象转数组的方法小结
2018/03/26 Javascript
详解vue-cli 2.0配置文件(小结)
2019/01/14 Javascript
layer 刷新某个页面的实现方法
2019/09/05 Javascript
Vue+iview+webpack ie浏览器兼容简单处理
2019/09/20 Javascript
node.js express框架实现文件上传与下载功能实例详解
2019/10/15 Javascript
python fabric使用笔记
2015/05/09 Python
Python实现快速排序和插入排序算法及自定义排序的示例
2016/02/16 Python
python版学生管理系统
2018/01/10 Python
Python实现多进程的四种方式
2019/02/22 Python
Python中的pathlib.Path为什么不继承str详解
2019/06/23 Python
调整Jupyter notebook的启动目录操作
2020/04/10 Python
Python 如何创建一个简单的REST接口
2020/07/30 Python
Lacoste美国官网:经典POLO衫品牌
2016/10/12 全球购物
微软澳洲官方网站:Microsoft Australia
2017/01/10 全球购物
世界上最悠久的自行车制造商:Ribble Cycles
2017/03/18 全球购物
五十岁生日宴会答谢词
2014/01/15 职场文书
《哪吒闹海》教学反思
2014/02/28 职场文书
保送生自荐信范文
2015/03/26 职场文书
资金申请报告范文
2015/05/14 职场文书
微信小程序和php的登录实现
2021/04/01 PHP