Есть ли способ скопировать текст в буфер обмена (multi-browser) в Angular2 Typescript framework?
Я нахожу только источники использования Javascript, например
document.execCommand('copy')
Есть ли способ скопировать текст в буфер обмена (multi-browser) в Angular2 Typescript framework?
Я нахожу только источники использования Javascript, например
document.execCommand('copy')
Вы можете реализовать директиву Angular2, используя clipboard.js библиотеку.
Сначала настройте библиотеку в 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.
Престижность @ThierryTemplier,
Основываясь на его ответе, я собрал директиву и разделил на github и npm.
Вот проект на github
ОБНОВЛЕНИЕ: 4/30/2017
Эта библиотека больше не зависит от clipboard.js.
Просто Angular!
У меня есть только один метод из 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);
}
В настоящее время реализованы только самые распространенные аббревиатуры API, в основном для передачи различных реализаций при запуске на сервере (рендеринг на стороне сервера (https://github.com/angular/universal) внутри веб-сайта, где API недоступен.
Я уверен, что еще нет ничего для API буфера обмена. Однако есть планы внедрить больше оберток.
Это простой чистый Angular2 и javascript решение, в котором не требуется никаких библиотек и которые могут использоваться в angular. Вы можете превратить его в сервис или сделать его более общим, если это необходимо, но это установит основную идею.
В настоящее время браузеры разрешают копирование текста в буфер обмена из Выбор в <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 для получения текста и копирования в буфер обмена.
Функция использует стандартный javascript для получения элемента по его идентификатору, выбирает его, выполняет команду "Копировать" на выбор и затем отменяет его.
Указанный вами код - это правильный способ сделать это, и это можно сделать и в 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();
}
Вот простой код, если ваш текст не находится внутри ввода или textarea, но div или любой другой элемент HTMLElement:
window.getSelection().selectAllChildren(document.getElementById('yourID');
document.execCommand("Copy");
Мне не удалось использовать команду select()
, потому что она не была распознана Angular. Надеюсь, это поможет кому-то!
Ben Nadel имел отличный пример, который работал для любого типа элемента html и не полагался на что-либо, что нужно установить. См. Сообщение блога Бена Или см. 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 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>