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 DragDropMixinperilaku seret-lepas dari komponen ini. Baik komponen yang dapat diseret maupun yang dapat dilepas menggunakan campuran yang sama.
Di dalam configureDragDrop, kita perlu memanggil registerTypesetiap kebiasaan kita ItemTypesyang didukung komponen. Misalnya, mungkin ada beberapa representasi gambar di aplikasi Anda, dan masing-masing akan menyediakan dragSourceuntukItemTypes.IMAGE .
A dragSourcehanyalah sebuah objek yang menentukan cara kerja sumber seret. Anda harus mengimplementasikan beginDraguntuk mengembalikan item yang mewakili data yang Anda seret dan, secara opsional, beberapa opsi yang menyesuaikan UI menyeret. Anda dapat menerapkan secara opsional canDraguntuk 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 dragSourceuntuk mereka.
Terakhir, Anda harus menggunakan {...this.dragSourceFor(itemType)}beberapa (satu atau lebih) elemen renderuntuk 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 ImageBlockmenjadi target penurunan untuk IMAGEs. Ini hampir sama, kecuali bahwa kita perlu memberikan registerTypesebuah dropTargetimplementasi:
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 dragSourceuntuk 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
dragPreviewuntuk Imagemenggunakan gambar sebagai tempat penampung seret (gunakan ImagePreloaderMixinuntuk memuatnya);
- Katakanlah, kami ingin membuat pemesanan ulang
ImageBlocks. Kami hanya membutuhkan mereka untuk diimplementasikan dropTargetdan dragSourceuntuk 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 .