详解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 相关文章推荐
Javascript和Ajax中文乱码吐血版解决方案
Dec 21 Javascript
js判断是否为数组的函数: isArray()
Oct 30 Javascript
js原型继承的两种方法对比介绍
Mar 30 Javascript
javascript实现分栏显示小技巧附图
Oct 13 Javascript
node.js解决获取图片真实文件类型的问题
Dec 20 Javascript
javascript实现控制div颜色
Jul 07 Javascript
JS中对象与字符串的互相转换详解
May 20 Javascript
Bootstrap基本组件学习笔记之分页(12)
Dec 08 Javascript
Node.js和Express简单入门介绍
Mar 24 Javascript
JavaScript实现图片本地预览功能【不用上传至服务器】
Sep 20 Javascript
Vue实现active点击切换方法
Mar 16 Javascript
微信小程序 高德地图路线规划实现过程详解
Aug 05 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
《魔兽世界》惊魂幻象将获得调整
2020/03/08 其他游戏
PHP面向对象之旅:深入理解static变量与方法
2014/01/06 PHP
ThinkPHP CURD方法之data方法详解
2014/06/18 PHP
重新认识php array_merge函数
2014/08/31 PHP
php根据某字段对多维数组进行排序的方法
2015/03/07 PHP
javascript cookies 设置、读取、删除实例代码
2010/04/12 Javascript
JavaScript之appendChild、insertBefore和insertAfter使用说明
2010/12/30 Javascript
使用GruntJS构建Web程序之合并压缩篇
2014/06/06 Javascript
Angularjs 创建可复用组件实例代码
2016/10/09 Javascript
js遍历获取表格内数据的方法(必看)
2017/04/06 Javascript
Node.js安装配置图文教程
2017/05/10 Javascript
JS jQuery使用正则表达式去空字符的简单实现代码
2017/05/20 jQuery
vue表单绑定实现多选框和下拉列表的实例
2017/08/12 Javascript
Node.js dgram模块实现UDP通信示例代码
2017/09/26 Javascript
详解Vue源码学习之callHook钩子函数
2018/07/25 Javascript
使用jquery DataTable和ajax向页面显示数据列表的方法
2018/08/09 jQuery
Vuex 快速入门(简单易懂)
2018/09/20 Javascript
vue文件运行的方法教学
2019/02/12 Javascript
Angular 多级路由实现登录页面跳转(小白教程)
2019/11/19 Javascript
原生JS实现微信通讯录
2020/06/18 Javascript
Python使用Pycrypto库进行RSA加密的方法详解
2016/06/06 Python
CentOS7.3编译安装Python3.6.2的方法
2018/01/22 Python
Python3实现的爬虫爬取数据并存入mysql数据库操作示例
2018/06/06 Python
python实现画五角星和螺旋线的示例
2019/01/20 Python
Python 监测文件是否更新的方法
2019/06/10 Python
Python搭建代理IP池实现接口设置与整体调度
2019/10/27 Python
Python3 集合set入门基础
2020/02/10 Python
德国最大的拼图在线商店:Puzzle.de
2016/12/17 全球购物
英国领先的在线药房:Pharmacy First
2017/09/10 全球购物
德国圣伯纳德草药屋:Kräuterhaus Sanct Bernhard(有中文站)
2018/08/05 全球购物
俄罗斯GamePark游戏商店网站:购买游戏、游戏机和配件
2020/03/13 全球购物
双拥工作宣传标语
2014/06/26 职场文书
质量在我心中演讲稿
2014/09/02 职场文书
心理健康教育培训研修感言
2015/11/18 职场文书
为什么node.js不适合大型项目
2021/04/28 Javascript
redis cluster支持pipeline的实现思路
2021/06/23 Redis