如何在 Angular 2 Typescript 中复制到剪贴板?
How do I copy to clipboard in Angular 2 Typescript?
有没有办法在 Angular2 Typescript 框架中复制剪贴板(多浏览器)中的文本?
我只找到使用 Javascript 的资源,例如
document.execCommand('copy')
目前只实现了最常见的APIs抽象,主要是为了能够在运行在服务器(服务器端渲染(https://github.com/angular/universal)中传递不同的实现在 API 不可用的网络工作者中。
我很确定剪贴板中还没有任何内容 API。不过,我们计划实施更多包装器。
您可以围绕 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>
我们希望能够通过指令将剪贴板附加到元素上,并提供我们想要 link 的 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。
感谢@ThierryTemplier,
根据他的回答,我在 github & npm 上整理了一个指令和分享。
这是github
上的项目
更新:2017 年 4 月 30 日
这个库不再依赖于 clipboard.js。
就Angular!
快速示例(组件代码):
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)
}
我只从 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);
}
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>
这是一个简单的 pure Angular2 和 javascript 解决方案 不需要任何库 并且可以在 angular 组件中使用。如果需要,您可以将其变成一项服务或使其更通用,但这将确立基本思想。
目前浏览器只允许将文本从 Selection 中的 <input>
或 [=13] 复制到剪贴板=]
在组件中做这样的事情:
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 获取元素,select 它,在 selection 上执行 "Copy" 命令,然后 deselect就这样了。
你提到的代码是正确的方法,它也可以在 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();
}
这是一个简单的代码,以防您的文本不在输入或文本区域内,而是 div 或任何其他 HTMLElement 并且您不想使用任何外部库:
window.getSelection().selectAllChildren(document.getElementById('yourID'));
document.execCommand("copy");
我无法使用 select()
命令,因为 Angular 无法识别它。希望这对某人有所帮助!
这是一种无需任何外部依赖或创建假元素即可实现此目的的方法,只需使用 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);
}
}
这是一个简单的纯 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();
}
有没有办法在 Angular2 Typescript 框架中复制剪贴板(多浏览器)中的文本?
我只找到使用 Javascript 的资源,例如
document.execCommand('copy')
目前只实现了最常见的APIs抽象,主要是为了能够在运行在服务器(服务器端渲染(https://github.com/angular/universal)中传递不同的实现在 API 不可用的网络工作者中。
我很确定剪贴板中还没有任何内容 API。不过,我们计划实施更多包装器。
您可以围绕 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>
我们希望能够通过指令将剪贴板附加到元素上,并提供我们想要 link 的 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。
感谢@ThierryTemplier,
根据他的回答,我在 github & npm 上整理了一个指令和分享。
这是github
上的项目更新:2017 年 4 月 30 日
这个库不再依赖于 clipboard.js。
就Angular!
快速示例(组件代码):
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)
}
我只从 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);
}
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>
这是一个简单的 pure Angular2 和 javascript 解决方案 不需要任何库 并且可以在 angular 组件中使用。如果需要,您可以将其变成一项服务或使其更通用,但这将确立基本思想。
目前浏览器只允许将文本从 Selection 中的 <input>
或 [=13] 复制到剪贴板=]
在组件中做这样的事情:
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 获取元素,select 它,在 selection 上执行 "Copy" 命令,然后 deselect就这样了。
你提到的代码是正确的方法,它也可以在 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();
}
这是一个简单的代码,以防您的文本不在输入或文本区域内,而是 div 或任何其他 HTMLElement 并且您不想使用任何外部库:
window.getSelection().selectAllChildren(document.getElementById('yourID'));
document.execCommand("copy");
我无法使用 select()
命令,因为 Angular 无法识别它。希望这对某人有所帮助!
这是一种无需任何外部依赖或创建假元素即可实现此目的的方法,只需使用 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);
}
}
这是一个简单的纯 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();
}