電子冒険:エピソード29:Vue正統ファイルマネージャ


すべての“主要な”フレームワークのうち、Vueは私が使用したものです、それは中国で最も人気があるように思えます、そして、それほどここにありません、それで、私は私のVueコードがすべてその偉大であると保証することができません.
しかし、それは冒険なので、とにかく試してみましょう.Vueアプリとしてエピソード27からSvelteファイルマネージャを実装しようとします.その後、しばらくの間、Svelteバージョンに戻るでしょう、しかし、あなたはVueで、または、あなたが好むどんな他のフレームワークででも続くことができます.

src / footer。Vue


これはSvelteバージョンとほぼ同じです<template> タグ、およびエクスポートしているものの小さな宣言を追加します.
すべてのものはsvelteで冗長です.ここでは、このような単純なコンポーネントのテンプレートの内容を書くことができます.
<script>
  export default {
    name: "Footer"
  }
</script>

<template>
  <footer>
    <button>F1 Help</button>
    <button>F2 Menu</button>
    <button>F3 View</button>
    <button>F4 Edit</button>
    <button>F5 Copy</button>
    <button>F6 Move</button>
    <button>F7 Mkdir</button>
    <button>F8 Delete</button>
    <button>F10 Quit</button>
  </footer>
</template>

<style>
  footer {
    text-align: center;
    grid-area: footer;
  }

  button {
    font-family: inherit;
    font-size: inherit;
    background-color: #66b;
    color: inherit;
  }
</style>

src / panelVue


このコンポーネントは、ファイルマネージャの1つのパネルに対して責任があります.スタイリングはSvelteバージョンと同じです.
<style>
  .left {
    grid-area: panel-left;
  }
  .right {
    grid-area: panel-right;
  }
  .panel {
    background: #338;
    margin: 4px;
  }
  .file {
    cursor: pointer;
  }
  .file.selected {
    color: #ff2;
    font-weight: bold;
  }
  .panel.active .file.focused {
    background-color: #66b;
  }
  .debug {
    max-width: 40vw;
  }
</style>
テンプレートはあまり悪くありません.Svelte ' sのように別々に各クラスをひっくり返す表現はありませんclass:a={conditionA} class:b={conditionB} , しかし、あなたはv-bind:class オブジェクト値v-bind:class={a: conditionA, b: conditionB} , どちらが多かれ少なかれ同じことです.
ループに入るv-for 要素の外側ではなく、各要素の属性.私は、それがより直観的でないとわかります、しかし、私はそれがもう少し簡潔であると思います.Svelteを知っていれば十分です.
<template>
  <div v-bind:class="{
        panel: true,
        active: active,
        left: (position==='left'),
        right: (position==='right'),
      }">
    <div
      v-for="file in files"
      v-bind:class="{
        file: true,
        focused: (file === focused),
        selected: (selected.includes(file)),
      }"
      @click="() => onclick(file)"
      @contextmenu="() => onrightclick(file)"
    >
      {{file}}
    </div>
  </div>
</template>
スクリプト部分はSvelte版より複雑です.
<script>
  export default {
    name: "Panel",
    props: ["position", "files", "active"],
    data: (e) => {
      return {
        focused: e.$props.files[0],
        selected: [],
      }
    },
    methods: {
      onclick: function(file) {
        this.$data.focused = file
        this.$emit("activate")
      },
      onrightclick: function(file) {
        this.$data.focused = file
        this.$emit("activate")
        this.flipSelected(file)
      },
      flipSelected: function(file) {
        if (this.$data.selected.includes(file)) {
          this.$data.selected = this.$data.selected.filter(f => f !== file)
        } else {
          this.$data.selected = [...this.$data.selected, file]
        }
      },
      goUp: function() {
        let i = this.$props.files.indexOf(this.$data.focused)
        if (i > 0) {
          this.$data.focused = this.$props.files[i - 1]
        }
      },
      goDown: function() {
        let i = this.$props.files.indexOf(this.$data.focused)
        if (i < this.$props.files.length - 1) {
          this.$data.focused = this.$props.files[i + 1]
        }
      },
      handleKey: function(e) {
        if (!this.$props.active) {
          return
        }
        if (e.key === "ArrowDown") {
          e.preventDefault()
          this.goDown()
        }
        if (e.key === "ArrowUp") {
          e.preventDefault()
          this.goUp()
        }
        if (e.key === " ") {
          e.preventDefault()
          this.flipSelected(this.$data.focused)
          this.goDown()
        }
      },
    },
    mounted() {
      window.addEventListener("keydown", this.handleKey)
    },
  }
</script>
ここで何が起こっているのですか.
  • 我々のコンポーネントがAであると宣言しますPanel
  • プロパティを宣言します.また、それらの型、妥当性、およびいくつかの追加属性をここで指定することができます
  • 初期状態を宣言するdata 初期状態を返す関数this.$props
  • 全ての方法はmethods 辞書、内部にアクセスすることができますthis.$data , this.$props
  • イベントを通して親と呼ぶことができますthis.$emit , または、propsとしてコールバックを渡すことによって- svelteも両方のメカニズムをサポートし、Vueとsvelteのドキュメントは、どちらを促進するかについて異なりますが、本当にそれはあなた次第です
  • メソッドは、this.methodName(...)
  • この部分は私をつかんだfunction() スタイル関数=> スタイルの矢印関数this が正しくない
  • がない<svelte:window> イベントリスナーを添付して自動的に分離することができますmounted() ライフサイクルフック一般的にコールする必要がありますwindow.removeEventListener コンポーネントがアンマウントされているとき、それはちょうど私たちのアプリは何か
  • Vue vs svelteの例


    VueとSvelteの間の1つの小さな機能を比較するために、Svelteは私たちにたくさんのthis.$stuff , しかし、それ以外は非常に類似した流れに従います.
    // Vue
    goUp: function() {
      let i = this.$props.files.indexOf(this.$data.focused)
      if (i > 0) {
        this.$data.focused = this.$props.files[i - 1]
      }
    },
    
    // Svelte
    let goUp = () => {
      let i = files.indexOf(focused)
      if (i > 0) {
        focused = files[i - 1]
      }
    }
    

    src / appVue


    これはより簡単なコンポーネントです.グローバルスタイルとコンポーネントのスタイルは別のタグに入ります
    <style global>
      body{
        background-color: #226;
        color: #fff;
        font-family: monospace;
        margin: 0;
        font-size: 16px;
      }
    </style>
    
    <style>
      .ui {
        width: 100vw;
        height: 100vh;
        display: grid;
        grid-template-areas:
          "header header"
          "panel-left panel-right"
          "footer footer";
        grid-template-columns: 1fr 1fr;
        grid-template-rows: auto 1fr auto;
      }
      .ui header {
        grid-area: header;
      }
      header {
        font-size: 24px;
        margin: 4px;
      }
    </style>
    
    テンプレートは、Svelteで行われたことに非常に近いです.
    <template>
      <div class="ui">
        <header>
          File Manager
        </header>
        <Panel
          v-bind:files=filesLeft
          position="left"
          v-bind:active="(activePanel === 'left')"
          @activate="activateLeft"
        />
        <Panel
          v-bind:files=filesRight
          position="right"
          v-bind:active="(activePanel === 'right')"
          @activate="activateRight"
        />
        <Footer />
      </div>
    </template>
    
    私たちは@activate 特定のコンポーネントを発するときに何をするかactivate イベント.
    そして、スクリプト部分では、我々が使用するコンポーネントの明示的なリストのような、Svelteのバージョンより少し多くのboilerplateを持ちます
    <script>
      import Panel from "./Panel.vue"
      import Footer from "./Footer.vue"
    
      export default {
        name: "App",
        components: {
          Panel,
          Footer,
        },
        data: () => ({
          filesLeft: [
            "Cat.js",
            "ipsum.js",
            "dolor.js",
            "sit.js",
            "amet.js",
            "walk.js",
            "on.js",
            "keyboard.js",
            "hide.js",
            "when.js",
            "guests.js",
            "come.js",
            "over.js",
            "play.js",
            "with.js",
            "twist.js",
            "ties.js",
          ],
          filesRight: [
            "Ask.png",
            "to.png",
            "be.png",
            "pet.png",
            "then.png",
            "attack.png",
            "owners.png",
            "hand.png",
            "need.png",
            "to.jpg",
            "chase.png",
            "tail.png",
          ],
          activePanel: "left",
        }),
        methods: {
          activateLeft: function() {
            this.$data.activePanel = "left"
          },
          activateRight: function() {
            this.$data.activePanel = "right"
          },
          handleKey: function(e) {
            if (e.key === "Tab") {
              e.preventDefault()
              if (this.$data.activePanel === "left") {
                this.$data.activePanel = "right"
              } else {
                this.$data.activePanel = "left"
              }
            }
          }
        },
        mounted() {
          window.addEventListener("keydown", this.handleKey)
        },
      }
    </script>
    

    結果


    結果を以下に示します.

    私が言及したように、私はVueをあまり使用していないので、私はここで本当に明白な何かを逃しました.もしそうならば、知らせてください.
    次のエピソードでは、私たちのSvelteアプリに戻って、それは実際のファイルだけではなく、静的な模擬データで動作します.
    いつものように.all the code for the episode is here .