Saya menerapkan react-dnd , mixin seret dan lepas HTML5 yang fleksibel untuk Bereaksi dengan kontrol DOM penuh.
Pustaka seret dan lepas yang ada tidak sesuai dengan kasus penggunaan saya, jadi saya menulisnya sendiri. Ini mirip dengan kode yang telah kami jalankan selama sekitar satu tahun di Stampsy.com, tetapi ditulis ulang untuk memanfaatkan React dan Flux.
Persyaratan utama yang saya miliki:
- Emisi nol DOM atau CSS-nya sendiri, serahkan pada komponen yang memakan;
- Tetapkan struktur sesedikit mungkin untuk mengonsumsi komponen;
- Gunakan seret dan lepas HTML5 sebagai backend utama tetapi memungkinkan untuk menambahkan backend yang berbeda di masa mendatang;
- Seperti API HTML5 asli, tekankan menyeret data dan bukan hanya "tampilan yang dapat diseret";
- Sembunyikan kebiasaan API HTML5 dari kode konsumsi;
- Komponen yang berbeda mungkin berupa "sumber seret" atau "target jatuhkan" untuk jenis data yang berbeda;
- Izinkan satu komponen berisi beberapa sumber seret dan jatuhkan target bila diperlukan;
- Permudah target drop untuk mengubah tampilannya jika data yang kompatibel sedang diseret atau di-hover;
- Permudah penggunaan gambar untuk menyeret thumbnail alih-alih screenshot elemen, menghindari kebiasaan browser.
Jika ini terdengar asing bagi Anda, baca terus.
Pemakaian
Sumber Drag Sederhana
Pertama, nyatakan jenis data yang bisa diseret.
Ini digunakan untuk memeriksa "kompatibilitas" sumber seret dan target pelepasan:
module.exports = {
BLOCK: 'block',
IMAGE: 'image'
};
(Jika Anda tidak memiliki beberapa tipe data, perpustakaan ini mungkin bukan untuk Anda.)
Kemudian, mari kita buat komponen yang dapat diseret sangat sederhana yang, saat diseret, mewakili IMAGE
:
var { DragDropMixin } = require('react-dnd'),
ItemTypes = require('./ItemTypes');
var Image = React.createClass({
mixins: [DragDropMixin],
configureDragDrop(registerType) {
registerType(ItemTypes.IMAGE, {
dragSource: {
beginDrag() {
return {
item: this.props.image
};
}
}
});
},
render() {
return (
<img src={this.props.image.url}
{...this.dragSourceFor(ItemTypes.IMAGE)} />
);
}
);
Dengan menentukan configureDragDrop
, kami memberi tahu DragDropMixin
perilaku seret-lepas dari komponen ini. Baik komponen yang dapat diseret maupun yang dapat dilepas menggunakan campuran yang sama.
Di dalam configureDragDrop
, kita perlu memanggil registerType
setiap kebiasaan kita ItemTypes
yang didukung komponen. Misalnya, mungkin ada beberapa representasi gambar di aplikasi Anda, dan masing-masing akan menyediakan dragSource
untukItemTypes.IMAGE
.
A dragSource
hanyalah sebuah objek yang menentukan cara kerja sumber seret. Anda harus mengimplementasikan beginDrag
untuk mengembalikan item yang mewakili data yang Anda seret dan, secara opsional, beberapa opsi yang menyesuaikan UI menyeret. Anda dapat menerapkan secara opsional canDrag
untuk melarang menyeret, atau endDrag(didDrop)
untuk menjalankan beberapa logika saat penurunan telah (atau belum) terjadi. Dan Anda dapat membagikan logika ini di antara komponen dengan membiarkan mixin bersama membuatkan dragSource
untuk mereka.
Terakhir, Anda harus menggunakan {...this.dragSourceFor(itemType)}
beberapa (satu atau lebih) elemen render
untuk memasang penangan tarik. Ini berarti Anda dapat memiliki beberapa "pegangan seret" dalam satu elemen, dan mereka bahkan mungkin sesuai dengan jenis item yang berbeda. (Jika Anda tidak terbiasa dengan JSX Spread Attributes sintaks , periksalah).
Target Jatuhkan Sederhana
Katakanlah kita ingin ImageBlock
menjadi target penurunan untuk IMAGE
s. Ini hampir sama, kecuali bahwa kita perlu memberikan registerType
sebuah dropTarget
implementasi:
var { DragDropMixin } = require('react-dnd'),
ItemTypes = require('./ItemTypes');
var ImageBlock = React.createClass({
mixins: [DragDropMixin],
configureDragDrop(registerType) {
registerType(ItemTypes.IMAGE, {
dropTarget: {
acceptDrop(image) {
DocumentActionCreators.setImage(this.props.blockId, image);
}
}
});
},
render() {
return (
<div {...this.dropTargetFor(ItemTypes.IMAGE)}>
{this.props.image &&
<img src={this.props.image.url} />
}
</div>
);
}
);
Seret Sumber + Jatuhkan Target Dalam Satu Komponen
Katakanlah kita sekarang ingin pengguna dapat menarik keluar gambar ImageBlock
. Kami hanya perlu menambahkan yang sesuai dragSource
untuk itu dan beberapa penangan:
var { DragDropMixin } = require('react-dnd'),
ItemTypes = require('./ItemTypes');
var ImageBlock = React.createClass({
mixins: [DragDropMixin],
configureDragDrop(registerType) {
registerType(ItemTypes.IMAGE, {
dragSource: {
canDrag() {
return !!this.props.image;
},
beginDrag() {
return {
item: this.props.image
};
}
}
dropTarget: {
acceptDrop(image) {
DocumentActionCreators.setImage(this.props.blockId, image);
}
}
});
},
render() {
return (
<div {...this.dropTargetFor(ItemTypes.IMAGE)}>
{/* Add {...this.dragSourceFor} handlers to a nested node */}
{this.props.image &&
<img src={this.props.image.url}
{...this.dragSourceFor(ItemTypes.IMAGE)} />
}
</div>
);
}
);
Apa Lagi yang Mungkin?
Saya belum membahas semuanya tetapi mungkin untuk menggunakan API ini dalam beberapa cara lagi:
- Gunakan
getDragState(type)
dangetDropState(type)
untuk mempelajari apakah menyeret aktif dan menggunakannya untuk mengalihkan kelas atau atribut CSS;
- Tentukan
dragPreview
untuk Image
menggunakan gambar sebagai tempat penampung seret (gunakan ImagePreloaderMixin
untuk memuatnya);
- Katakanlah, kami ingin membuat pemesanan ulang
ImageBlocks
. Kami hanya membutuhkan mereka untuk diimplementasikan dropTarget
dan dragSource
untuk ItemTypes.BLOCK
.
- Misalkan kita menambahkan jenis blok lainnya. Kita dapat menggunakan kembali logika penyusunan ulang mereka dengan menempatkannya dalam sebuah mixin.
dropTargetFor(...types)
memungkinkan untuk menentukan beberapa jenis sekaligus, sehingga satu zona tetesan dapat menangkap berbagai jenis.
- Saat Anda membutuhkan kontrol yang lebih halus, sebagian besar metode akan meneruskan peristiwa tarik yang menyebabkannya sebagai parameter terakhir.
Untuk dokumentasi terbaru dan instruksi instalasi, kunjungi repo react-dnd di Github .