Angular 2:实现自定义上下文菜单

2024-04-21

我正在实现 Angular 2 属性指令,以允许我向元素添加自定义上下文菜单,如下所示:

<p context-menu="myItems">Hello world</p>

该指令添加了一个鼠标事件处理程序来捕获右键单击,其想法是构建一个上下文菜单,将其添加到 DOM,然后在用户完成操作时销毁它。

我有一个实现上下文菜单本身的组件。我想构造该组件,调用它的方法来设置项目列表,然后将其添加到 DOM。

看来我可以使用 AppViewManager.createHostViewInContainer 来做到这一点。这是执行此操作的适当方法吗?如果是这样,有没有办法构造/获取 ElementRef 来document.body这样我就可以告诉 createHostViewInContainer 在那里构造组件?显然,我不希望我的菜单被剪切在我要添加上下文菜单的元素内。


这是我认为的一个好方法。
您需要 1 个服务、1 个组件和 1 个指令。

这是一个笨蛋 http://plnkr.co/edit/3klGukkbDBCOaBYqcGmr?p=preview

解释:

服务ContextMenuService:

  • 提供一个主题类型{event:MouseEvent,obj:any[]}成为 订阅者ContextMenuHolderComponent,并接收值 从ContextMenuDirective

Code:

import {Injectable} from 'angular2/core';
import {Subject} from 'rxjs/Rx';

@Injectable()
export class ContextMenuService{

    public show:Subject<{event:MouseEvent,obj:any[]}> = new Subject<{event:MouseEvent,obj:any[]}>();
}

并将其添加到提供者列表中bootstrap()

bootstrap(AppComponent,[ContextMenuService]);

组件ContextMenuHolderComponent:

  • 该组件被添加到根组件内。例如AppComponent它有一个fixed位置。
  • 它订阅了subject in ContextMenuService受到:

    1. 菜单项类型{title:string,subject:Subject}[],主题用于发送菜单内点击的值
    2. 鼠标事件对象
  • 它有一个(document:click)事件侦听器,用于在菜单外部单击时关闭菜单。

code:

@Component({
  selector:'context-menu-holder',
  styles:[
    '.container{width:150px;background-color:#eee}',
    '.link{}','.link:hover{background-color:#abc}',
    'ul{margin:0px;padding:0px;list-style-type: none}'
  ],
  host:{
    '(document:click)':'clickedOutside()'
  },
  template:
  `<div [ngStyle]="locationCss" class="container">
      <ul>
          <li (click)="link.subject.next(link.title)" class="link" *ngFor="#link of links">
              {{link.title}}
          </li>
      </ul>
    </div>
  `
})
class ContextMenuHolderComponent{
  links = [];
  isShown = false;
  private mouseLocation :{left:number,top:number} = {left:0;top:0};
  constructor(private _contextMenuService:ContextMenuService){
    _contextMenuService.show.subscribe(e => this.showMenu(e.event,e.obj));
  }
  // the css for the container div
  get locationCss(){
    return {
      'position':'fixed',
      'display':this.isShown ? 'block':'none',
      left:this.mouseLocation.left + 'px',
      top:this.mouseLocation.top + 'px',
    };
  }
  clickedOutside(){
    this.isShown= false; // hide the menu
  }

  // show the menu and set the location of the mouse
  showMenu(event,links){
    this.isShown = true;
    this.links = links;
    this.mouseLocation = {
      left:event.clientX,
      top:event.clientY
    }
  }
}

并将其添加到根组件中:

@Component({
    selector: 'my-app',
    directives:[ContextMenuHolderComponent,ChildComponent],
    template: `
    <context-menu-holder></context-menu-holder>
    <div>Whatever contents</div>
    <child-component></child-component>
    `
})
export class AppComponent { }

最后一个,ContextMenuDirective:

  • 它添加了一个contextmenu事件到宿主元素。
  • 接受要传递到的项目列表的输入ContextMenuHolderComponent.

Code:

@Directive({
  selector:'[context-menu]',
  host:{'(contextmenu)':'rightClicked($event)'}
})
class ContextMenuDirective{
  @Input('context-menu') links;
  constructor(private _contextMenuService:ContextMenuService){
  }
  rightClicked(event:MouseEvent){
    this._contextMenuService.show.next({event:event,obj:this.links});
    event.preventDefault(); // to prevent the browser contextmenu
  }
}

就是这样。您现在需要做的就是附加[context-menu]指令到一个元素并将其绑定到一个项目列表。例如:

@Component({
  selector:'child-component',
  directives:[ContextMenuDirective],
  template:`
  <div [context-menu]="links" >right click here ... {{firstRightClick}}</div>
  <div [context-menu]="anotherLinks">Also right click here...{{secondRightClick}}</div>
  `
})
class ChildComponent{
  firstRightClick; secondRightClick;
  links;
  anotherLinks;
  constructor(){
    this.links = [
      {title:'a',subject:new Subject()},
      {title:'b',subject:new Subject()},
      {title:'b',subject:new Subject()}
    ];
    this.anotherLinks = [
      {title:'link 1',subject:new Subject()},
      {title:'link 2',subject:new Subject()},
      {title:'link 3',subject:new Subject()}
    ];
  }

  // subscribe to subjects
  ngOnInit(){
    this.links.forEach(l => l.subject.subscribe(val=> this.firstCallback(val)));
    this.anotherLinks.forEach(l => l.subject.subscribe(val=> this.secondCallback(val)))
  }
  firstCallback(val){
    this.firstRightClick = val;
  }
  secondCallback(val){
    this.secondRightClick = val;
  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Angular 2:实现自定义上下文菜单 的相关文章

随机推荐

  • 如何找到第一个设置位的索引

    是否有按位解决方案来查找仅设置一个位的掩码中第一个设置位的索引 例如对于 8 则为 3 对于 16 gt 4 依此类推 请不要循环 我能想到的最佳解决方案是创建位到索引的映射 function firstBit x return Math
  • 如何为 HTML5 画布上下文设置 2 种字体?

    我试图让画布在绘制文本时使用两种字体 这是因为我的主要字体是 Comic Sans MS 这是一个儿童应用程序 由于我在 iPad 上找不到 Comic Sans 因此我尝试用 MarkerFelt Thin 来替代它 我尝试使用以下语句的
  • 如何在 powershell 提示符中使用波形符?

    所以我明白了 function global prompt Commands go here 在 powershell 中设置提示符 我可以用Get Location获取当前工作目录 我可以cd 并在我的主目录中 但是我可以让提示使用波浪号
  • 如何连接Kafka和Elasticsearch?

    我是Kafka的新手 我使用kafka通过logstash收集netflow 可以 并且我想将数据从kafka发送到elasticsearch 但是存在一些问题 我的问题是如何将 Kafka 与 Elasticsearch 连接起来 net
  • 无法从量角器测试中的元素值返回字符串

    因此 我试图从解决此承诺的元素值中获取要返回的字符串值 我想将原始字符串值传递给我在量角器测试中构建的另一个函数 这是元素 div div
  • 如何保证成员4字节对齐?

    为了使用 OSAtomicDecrement mac 特定的原子操作 我需要提供一个 4 字节对齐的 SInt32 这样的煮法有用吗 还有其他方法可以解决对齐问题吗 struct SomeClass SomeClass member sto
  • Cassandra cli:将十六进制值转换为人类可读的格式

    我开始于卡桑德拉 questions tagged cassandra 当我跑步时list or get命令在cassandra cli questions tagged cassandra cli 我得到这样的结果 default use
  • 检查用户是否登录时未定义 nil

    我想使用 Firebase 来检测用户是否登录 var auth new FirebaseSimpleLogin Ref function err user if err console log err else if user conso
  • 启动脚本似乎不起作用

    我最近开始在我的一些项目中使用 Google 的计算引擎 问题是我的启动脚本似乎不起作用 由于某种原因我的脚本不起作用 虚拟机具有启动脚本元数据并且工作正常当我手动运行它时 sudo google metadata script runne
  • 如何根据百分比更改imageview中的图像颜色并将颜色填充到该百分比

    如何根据百分比填充图像TextView 它应该根据百分比变化TextView 在下面的代码中 高度布局正在改变 但我希望图像的颜色应该根据百分比 textview 电池 的值 改变 CODE private void displayData
  • 如何将 NSTimer 与这个简单的 while 循环一起使用?

    我有一个正在执行的 void 方法 在某一时刻它会进入一个 while 循环 该循环在请求时直接从加速度计获取值 我浏览了有关 NSTimer 类的文档 但我无法理解在我的情况下如何准确地使用这个对象 e g void play if ac
  • 使用代码将 X509 证书添加到存储区

    此代码会将 x509 cer 证书文件添加到证书存储中 使用System Security Cryptography X509Certificates var filename Cert cer var cert new X509Certi
  • Selenium 服务器错误:无法获取浏览器

    我在 Windows 7 上运行 Selenium Standalone Server 2 25 并使用 Internet Explorer 9 作为浏览器 对于每个需要打开浏览器的测试 我都会收到此错误 Selenium WebDrive
  • 在复合组件的属性中使用EL

    我的 JSF 自定义组件代码
  • 在 Jest .toMatchObject 中包含 toBeCloseTo

    我正在测试一个对象是否与一组字段匹配 但其中一个是浮点 我需要使用 toBeClearTo https jestjs io docs en next expect tobeclosetonumber numdigits 怎么可能在一段时间之
  • r 中不包括 NA 的列长度

    假设我有一个data frame如下 a b c 1 5 NA 6 2 NA NA 7 3 6 5 8 我想找到每列的长度 不包括 NA 答案应该是这样的 a b c 2 1 3 到目前为止 我已经尝试过 is na Gives TRUE
  • Excel公式从日期中减去天数

    Excel中有没有办法让公式执行如下操作 12 20 2010 180 这需要特定日期 本例中为 12 20 2010 并减去 180 天 假设原始日期位于单元格 A1 中 DATE YEAR A1 MONTH A1 DAY A1 180
  • 为什么 jquery 脚本不工作?

    为什么 jQuery 脚本可以在我的 jsfiddle 中运行 但不能在我的页面中运行 我所做的 尝试了不同版本的 JQuery 制作了脚本 所以我有这个测试页面 头部部分
  • 如何使用 Xcode 5 本地化我的应用程序?

    这是关于的后续问题 和答案 如何使用 Xcode 4 本地化我的应用程序 https stackoverflow com questions 5349066 how to localize my app with xcode 4 11282
  • Angular 2:实现自定义上下文菜单

    我正在实现 Angular 2 属性指令 以允许我向元素添加自定义上下文菜单 如下所示 p Hello world p 该指令添加了一个鼠标事件处理程序来捕获右键单击 其想法是构建一个上下文菜单 将其添加到 DOM 然后在用户完成操作时销毁