如何在Angular 2 Typescript中复制到剪贴板?

时间:2016-03-31 08:34:21

标签: angular clipboard.js

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

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

document.execCommand('copy')

10 个答案:

答案 0 :(得分:35)

您可以在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

答案 1 :(得分:23)

感谢@ThierryTemplier,

根据他的回答,我整理了一个指令并分享了github&amp; NPM。

以下是github

上的项目

更新时间:4/30/2017

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

Just Angular!

答案 2 :(得分:21)

我从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);
}

答案 3 :(得分:3)

这是一个简单的纯Angular2 javascript 解决方案, 不需要任何库 ,哪些可以用于角度分量。如果需要,您可以将其转换为服务或使其更通用,但这将建立基本想法。

目前浏览器只允许通过<input><textarea>

中的 选择 将文本复制到剪贴板

在组件中执行以下操作:

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获取元素,选择它,在选择上执行“复制”命令,然后取消选择它。

答案 4 :(得分:2)

如果您的文本不在输入或textarea中,而是div或任何其他HTMLElement,这是一个简单的代码:

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

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

答案 5 :(得分:1)

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

我很确定剪贴板API还没有。有计划实施更多包装。

答案 6 :(得分:0)

您提到的代码是正确的方法,也可以在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();
}

答案 7 :(得分:0)

这是一种在没有任何外部依赖或创建虚假元素的情况下实现此目的的方法,只能使用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?

答案 8 :(得分:0)

这是一个简单的纯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();
}

答案 9 :(得分:-1)

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>