Panda Noir

JavaScript の限界を究めるブログでした。最近は幅広めに書いてます。

Svelteでドラッグ&ドロップでファイル選択できるinput要素を作った

以前ドラッグ&ドロップでファイル選択できるinput要素をVue.jsで作りました。それを今度はSvelteに書き直してみました。ついでに得た知見も披露します。

デモ

まずは完成品をご覧ください。

デモ

前回つくったものと動作自体は同じですので、詳しい説明は省略します。

使い方

<div id="drag"></div>
<script src="https://pandanoir.net/js/drag.js"></script>
<script>
  new Drag({
    target: document.getElementById('drag'),
    data: {
      name: 'hoge',
    },
  });
</script>

まず、drag.jsを読み込みます。次にnew Drag({target: element})と書きます。以上です。

dataにオブジェクトを渡すと、そのプロパティと値がfile-inputの属性として設定されます。

VueからSvelteへ変換するときに苦戦したこと

基本的にVueとSvelteは似ているので、

  • @clickon:click
  • :class="{hoge: fuga}"class:hoge="fuga"

とこののようにカンタンに変換ができます。

しかし、「コンポーネント内の特定の要素に、任意の属性値を設定したい」という部分が難しかったです。

親要素のプロパティはどこに行くべきか?

例えばVueで以下のようにしたら、input要素へnameとacceptは渡ってほしいですよね?

import drag from '../js/drag.vue';
const app = new Vue({
    el: '#app',
    components: {drag},
    template: `<drag name="upload_file" accpet=".png"/>`
});

これをVueではinheritAttrsをfalseにして、v-bind="$attrs$をコンポーネント内のinput要素につけることで、カンタンに実現できます。

しかし、Svelteではややトリッキーなことをしなければなりません。

まず、Vue.jsのような$attrsがありません。そのため、new Drag({ data: data })のようにdataで渡すようにします。

そして、これをbindするときも一癖あります。単に<input {...options.data}>としても、生成段階ではthis.optionsがありませんので、エラーが出ます。そのため、this.options.dataを一度受け取る作業を行います。

export default {
  oncreate() {
    this.set({
      props: this.options.data
    });
  },

あとは<input {...props}>としてやればOKです。