【问题标题】:How do I copy to clipboard in Angular 2 Typescript?如何在 Angular 2 Typescript 中复制到剪贴板?
【发布时间】:2016-07-19 14:20:19
【问题描述】:

有没有办法在Angular2 Typescript框架的剪贴板(多浏览器)中复制文本?

我只找到使用 Javascript 的来源,例如

document.execCommand('copy')

【问题讨论】:

  • 你可以使用ngxyz-c2c,有多种方法。

标签: angular clipboard.js


【解决方案1】:

这是一个简单的代码,以防您的文本不在输入或文本区域内,而是在 div 或任何其他 HTMLElement 中,并且您不想使用任何外部库:

window.getSelection().selectAllChildren(document.getElementById('yourID'));
document.execCommand("copy");

我无法使用 select() 命令,因为 Angular 无法识别它。希望这对某人有帮助!

【讨论】:

  • 如果您需要将文本放在 div 中并且仍想复制它,这是一个非常有用的解决方案。
  • 如果您要复制电子邮件之类的文本,格式也会被复制。因此,如果您将其粘贴到邮件客户端或 Gmail 中,您可以获得 HTML 格式。
【解决方案2】:

向@ThierryTemplier 致敬,

根据他的回答,我整理了一个指令并在 github 和 npm 上分享。

这是github上的项目

更新:2017 年 4 月 30 日

这个库不再依赖于 clipboard.js。

只是角度!

快速示例(组件代码):

import { ClipboardService } from 'ngx-clipboard'

...

constructor(private _clipboardService: ClipboardService){
...
}

// not sure, but this should the result of user interaction (e.g. (click) )
copyToClipboard(){
  const text = computeText();
  this._clipboardService.copyFromContent(text)
}

【讨论】:

  • 我安装了 'ngx-clipboard' 然后使用 import { ClipboardModule } from 'ngx-clipboard' 导入它并添加到我的应用程序模块中的@ngmodule [ClipboardModule] 但它仍然给我以下错误。未捕获的错误:在 CompileMetadataResolver._loadNgModuleMetadata (localhost:9080/vendor.bundle.js:12247:49) 的 Array.forEach (native) 的 localhost:9080/vendor.bundle.js:12262:31 处的模块“AppModule”导入了意外的值“ClipboardModule”......
  • 从你说的这很难看出。你试过 Github 上的演示代码吗?
  • @maxisam 它对我也不起作用。出现错误无法绑定到“ngxClipboard”,因为它不是“按钮”的已知属性。详情见这里:stackoverflow.com/questions/43062477/…
  • 您的仅适用于输入 html 元素。如果有办法让它适用于任何东西(如跨度或 p),请在您的自述文件中添加一个示例。否则,对于任何需要它的人来说,这个例子是复制/粘贴成功link
  • 它与 Angular 9 中的 ClipboardService 服务没有任何问题。还添加了一个快速示例,以了解将任意文本复制到剪贴板是多么容易。谢谢。
【解决方案3】:

这是一个简单的纯 Angular2 和 javascript 解决方案,不需要任何库,并且可以在 Angular 组件中使用。如果需要,您可以将其变成服务或使其更通用,但这将确立基本思想。

目前浏览器只允许将文本从 或 中的选择复制到剪贴板。这可以在 div 中实现

(.html file)
<div id="inputId">Some texts</div>
<button (click)="copyToClipboard()'>click me</button>

//(.ts file)

public copyToClipboard(){
  var el = document.getElementById('inputId');
  el.setAttribute('contenteditable','true');
  el.focus();
  document.execCommand('selectAll');
  document.execCommand('copy');
  el.setAttribute('contenteditable','false');
  el.blur();
}

【讨论】:

  • 感谢伙伴,即使我的内容在 div 中也能正常工作
【解决方案4】:

这是一个简单的 纯 Angular2javascript 解决方案,不需要任何库,并且可以用于角度分量。如果需要,您可以将其变成服务或使其更通用,但这将确立基本思想。

当前浏览器只允许将文本从&lt;input&gt;&lt;textarea&gt; 中的选择复制到剪贴板

在组件中做这样的事情:

import {Inject} from "@angular/core";
import {DOCUMENT} from "@angular/platform-browser";

export class SomeComponent {
    private dom: Document;

    constructor(@Inject(DOCUMENT) dom: Document) {        
       this.dom = dom;
    }

    copyElementText(id) {
        var element = null; // Should be <textarea> or <input>
        try {
            element = this.dom.getElementById(id);
            element.select();
            this.dom.execCommand("copy");
        }
        finally {
           this.dom.getSelection().removeAllRanges;
        }
    }
}

然后在与组件关联的html块中,执行以下操作:

<div>
   <button (click)="copyElementText('elem1')">Copy</button>
</div>
<textarea id="elem1">Some text</textarea>

就是这样!该按钮在其组件中调用 copyElementText() 函数,并将 html 元素的 ID 传递给它以从中获取文本并复制到剪贴板。

该函数使用标准 javascript 通过其 ID 获取元素,选择它,对选择执行“复制”命令,然后取消选择它。

【讨论】:

    【解决方案5】:

    这是一种无需任何外部依赖或创建虚假元素的方法,只需使用Clipboard API

    import { DOCUMENT } from '@angular/common';
    import { Directive, EventEmitter, HostListener, Inject, Input, Output } from '@angular/core';
    
    @Directive({
      selector: '[myClipboard]'
    })
    export class ClipboardDirective {
    
      @Input() myClipboard: string;
      @Output() myClipboardSuccess = new EventEmitter<ClipboardEvent>();
    
      constructor(@Inject(DOCUMENT) private document: Document) {}
    
      @HostListener('click')
      onClick() {
        this.document.addEventListener('copy', this.handler);
        this.document.execCommand('copy');
      }
    
      private handler = (e: ClipboardEvent) => {
        e.clipboardData.setData('text/plain', this.myClipboard);
        e.preventDefault();
        this.myClipboardSuccess.emit(e);
        this.document.removeEventListener('copy', this.handler);
      }
    
    }
    

    Can I use Clipboard API?

    【讨论】:

      【解决方案6】:

      您可以在 clipboard.js 库周围实现一个 Angular2 指令。

      首先将库配置成SystemJS:

      <script>
        System.config({
          map: {
            clipboard: 'https://cdn.rawgit.com/zenorocha/clipboard.js/master/dist/clipboard.js'
          },
          packages: {
            'app': {
              defaultExtension: 'js'
            }
          } 
        });
        (...)
      </script>
      

      我们希望能够通过指令将剪贴板附加到元素上,并提供我们想要链接的 DOM 元素作为参数。指定到指定目标元素中的值将用于复制其文本。这是一个使用示例:

      <div>
        <input #foo/>
        <button [clipboard]="foo">Copy</button>
      </div>
      

      该指令的实现如下:

      import {Directive,ElementRef,Input,Output,EventEmitter} from 'angular2/core';
      import Clipboard from 'clipboard';
      
      @Directive({
        selector: '[clipboard]'
      })
      export class ClipboardDirective {
        clipboard: Clipboard;
      
        @Input('clipboard')
        elt:ElementRef;
      
        @Output()
        clipboardSuccess:EventEmitter<any> = new EventEmitter();
      
        @Output()
        clipboardError:EventEmitter<any> = new EventEmitter();
      
        constructor(private eltRef:ElementRef) {
        }
      
        ngOnInit() {
          this.clipboard = new Clipboard(this.eltRef.nativeElement, {
            target: () => {
              return this.elt;
            }
          });
      
          this.clipboard.on('success', (e) => {
            this.clipboardSuccess.emit();
          });
      
          this.clipboard.on('error', (e) => {
            this.clipboardError.emit();
          });
        }
      
        ngOnDestroy() {
          if (this.clipboard) {
            this.clipboard.destroy();
          }
        }
      }
      

      请参阅此 plunkr 以获取示例:https://plnkr.co/edit/elyMcP5PX3UP4RkRQUG8?p=preview

      【讨论】:

      • 这是一个非常好的方法,但是在某些情况下,外部依赖项太多了 :),对于这些情况,简单的 js + angular 解决方案也应该是合适的stackoverflow.com/a/52949299/2583579
      【解决方案7】:

      你提到的代码是正确的方法,它也可以在 Angular 2+ 中完成。

      我不知道你究竟需要做什么,但如果你有一个输入和一个按钮:

      (.html file)
      
      <input id='inputId'></input>
      <button (click)="copyToClipboard()'>click me</button>
      

      那么你需要做的就是:

      (.ts file)
      
      public copyToClipboard(): void {
        const inputElement = document.getElementById('inputId');
        (<any>inputElement).select();
        document.execCommand('copy');
        inputElement.blur();
      }
      

      【讨论】:

        【解决方案8】:

        Ben Nadel 有一个很好的例子,它适用于任何 html 元素类型并且不依赖于任何要安装的东西。见Ben's blog post 或查看 Git gist

        查看他的博客了解更多关于它和他所做的日志记录,这里是相关的并稍作修改,所以它更适合这里:

        制作指令:clipboard.directive.ts

        // Import the core angular services.
        import { Directive } from "@angular/core";
        import { EventEmitter } from "@angular/core";
        
        // Import the application components and services.
        import { ClipboardService } from "./clipboard.service";
        
        // This directive acts as a simple glue layer between the given [clipboard] property
        // and the underlying ClipboardService. Upon the (click) event, the [clipboard] value
        // will be copied to the ClipboardService and a (clipboardCopy) event will be emitted.
        @Directive({
        selector: "[clipboard]",
        inputs: [ "value: clipboard" ],
        outputs: [
            "copyEvent: clipboardCopy",
            "errorEvent: clipboardError"
        ],
        host: {
            "(click)": "copyToClipboard()"
        }
        })
        export class ClipboardDirective {
        
        public copyEvent: EventEmitter<string>;
        public errorEvent: EventEmitter<Error>;
        public value: string;
        
        private clipboardService: ClipboardService;
        
        
        // I initialize the clipboard directive.
        constructor( clipboardService: ClipboardService ) {
        
            this.clipboardService = clipboardService;
            this.copyEvent = new EventEmitter();
            this.errorEvent = new EventEmitter();
            this.value = "";
        }
        
        // ---
        // PUBLIC METODS.
        // ---
        
        // I copy the value-input to the Clipboard. Emits success or error event.
        public copyToClipboard() : void {
            this.clipboardService
                .copy( this.value )
                .then(
                    ( value: string ) : void => {
        
                        this.copyEvent.emit( value );
        
                    }
                )
                .catch(
                    ( error: Error ) : void => {
        
                        this.errorEvent.emit( error );
                    }
                )
            ;
        }
        }
        

        还有一个服务clipboard.service.ts

        // Import the core angular services.
        import { DOCUMENT } from "@angular/platform-browser";
        import { Inject } from "@angular/core";
        import { Injectable } from "@angular/core";
        @Injectable()
        export class ClipboardService {
        
        private dom: Document;
        // I initialize the Clipboard service.
        // --
        // CAUTION: This service is tightly couped to the browser DOM (Document Object Model).
        // But, by injecting the "document" reference rather than trying to reference it
        // globally, we can at least pretend that we are trying to lower the tight coupling.
        constructor( @Inject( DOCUMENT ) dom: Document ) {
            this.dom = dom;
        }
        
        // ---
        // PUBLIC METHODS.
        // ---
        // I copy the given value to the user's system clipboard. Returns a promise that
        // resolves to the given value on success or rejects with the raised Error.
        public copy( value: string ) : Promise<string> {
            var promise = new Promise(
                ( resolve, reject ) : void => {
                    var textarea = null;
                    try {
                        // In order to execute the "Copy" command, we actually have to have
                        // a "selection" in the currently rendered document. As such, we're
                        // going to inject a Textarea element and .select() it in order to
                        // force a selection.
                        // --
                        // NOTE: This Textarea is being rendered off-screen.
                        textarea = this.dom.createElement( "textarea" );
                        textarea.style.height = "0px";
                        textarea.style.left = "-100px";
                        textarea.style.opacity = "0";
                        textarea.style.position = "fixed";
                        textarea.style.top = "-100px";
                        textarea.style.width = "0px";
                        this.dom.body.appendChild( textarea );
        
                        // Set and select the value (creating an active Selection range).
                        textarea.value = value;
                        textarea.select();
                        // Ask the browser to copy the current selection to the clipboard.
                        this.dom.execCommand( "copy" );
                        resolve( value );
                    } finally {
                        // Cleanup - remove the Textarea from the DOM if it was injected.
                        if ( textarea && textarea.parentNode ) {
        
                            textarea.parentNode.removeChild( textarea );
                        }
                    }
                }
            );
            return( promise );
        }
        }
        

        在 app.module.ts 中同时导入,然后你可以在 html 中引用它,如下所示:

        <p>
                <button [clipboard]="value1.innerHTML.trim()">
                    Copy Text
                </button>
                <span #value1>
                    Hello World!
                </span>
            </p>
        

        【讨论】:

          【解决方案9】:

          我只从https://github.com/pehu71/copy-component/blob/master/src/simple/copy.component.ts 得到了一种方法 甚至适用于 android 4.1.2

          copy(val) {
          
              let selBox = document.createElement('textarea');
          
              selBox.style.position = 'fixed';
              selBox.style.left = '0';
              selBox.style.top = '0';
              selBox.style.opacity = '0';
              selBox.value = val;
          
              document.body.appendChild(selBox);
              selBox.focus();
              selBox.select();
          
              document.execCommand('copy');
              document.body.removeChild(selBox);
          }
          

          【讨论】:

          • 老兄,把这个发布到 npm 上!!。
          • 我喜欢它!没有额外的包——只有几行代码。完美。
          【解决方案10】:

          目前仅针对最常见的 API 实现了抽象,主要是为了能够在服务器上运行时传递不同的实现(服务器端渲染 (https://github.com/angular/universal) 在 API 不可用的 webworker 内部)。

          我很确定剪贴板 API 还没有任何内容。不过有计划实施更多的包装器。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-10-12
            • 2018-08-12
            • 1970-01-01
            • 1970-01-01
            • 2021-10-30
            • 2011-04-27
            相关资源
            最近更新 更多