【问题标题】:Vue 3 Reaching through components uses wrong functionVue 3 通过组件到达使用错误的功能
【发布时间】:2021-09-26 23:33:33
【问题描述】:

我在读取文件并将其到达父组件时遇到了以下问题。

首先我在 FileReaderComponent 上有一个 FileInput,当文件被更改时,它会发送一个 emit('change', file.content)。 顶部组件获取 file.content 并将其设置为 FileViewerComponent 的 Input Prop。 到目前为止,它按预期工作。但是当我添加第二个 FileReaderComponent 时,它的 Content 应该显示在第二个 FileViewerComponent 中。 但它总是使用第一个 FileReaderComponent 中的 @change。

我对 Vue 很陌生。我建立了一个最小的例子来展示: 相同的行为。当我使用第二个 FileReaderComponent 时,它应该将数据放入 readerOutput2 但出于某种原因它会将数据放入 readerOutput1。

我不知道我做错了什么。

App.vue

<template>
  <!-- <img alt="Vue logo" src="./assets/lpdLogo.svg" style="width: 100px; fill: green;"> -->
  <FileReaderComponent @change="data.readerOutput1 = $event"/>
  <FileViewerComponent v-model:input="data.readerOutput1"/>
  <FileReaderComponent @change="data.readerOutput2 = $event"/>
  <FileViewerComponent v-model:input="data.readerOutput2"/>
</template>

<script>
import FileReaderComponent from './components/FileReaderComponent.vue';
import FileViewerComponent from './components/FileViewerComponent.vue';
import { reactive } from 'vue';

export default {
  name: 'App',
  components: {
    FileReaderComponent,
    FileViewerComponent
  },
  setup () {
    const data = reactive({
      readerOutput1: '',
      readerOutput2: ''
    });
    
    function log(toLog) {
      console.log(toLog);
    }

    return { log, data }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

FileReaderComponent.vue

<template>
  <div id="fileUploadComponent" class="inline-flex items-center p-2 rounded border-2 border-yellow-500 m-1">
    <input type='file' id="fileInput" name="fileInput" @change="fileUploadChange()" ref="fileInput" class="hidden"/>
    <label for="fileInput" class="h-10 w-40 rounded text-gray-300 dark:text-gray-400 bg-gray-700 hover:bg-gray-500 text-xs" style="line-height: 2.5rem">
       <span class="block text-center w-full">Datei öffnen</span></label>
     <span id="filenamefield" class="inline-block m-2 text-gray-700 dark:text-gray-300">{{file.name}}</span>
  </div>
</template>

<script>
import {reactive} from 'vue';
export default {
  name: 'FileReaderComponent',
  emits: ['inFocus', 'submit', 'change'],
  props: {
    input: {
      type: String,
      required: false,
    }, 
  },
  methods : {
      setContent(content) {
        console.log('FileUpload, set Content', content)
        this.file.content = content;
        this.$emit('change', content);
    },
    fileUploadChange() {
        console.log('fileUploadChange triggered');
        this.file.input = this.$refs.fileInput.files[0];
        this.file.name = this.file.input.name;
        let file = this.file.input;

        let parent = this;
        parent.setContent('Content Loading')
        function onloadevent(evt) {
            parent.setContent(evt.target.result);
        }

        if (file) {
          var reader = new FileReader();
          reader.readAsText(file, "UTF-8");
          reader.onload = function (evt) {
              onloadevent(evt);
          }
          reader.onerror = function () {
              onloadevent('An Error occurred while reading File');
          }
        }
    }
  },
  setup(props, {emit}) {
      const file = reactive({
          name: 'Keine Ausgewählt',
          input: Element,
          content: String,
      })

      return {file}
  }
}

</script>

<style scoped>
    .inputfile {
        width: 0.1px;
        height: 0.1px;
        opacity: 0;
        overflow: hidden;
        position: absolute;
        z-index: -1;
    }

    .inputfile+label {
        font-weight: 700;
        display: inline-block;
    }

    input:checked+svg {
        display: block;
    }
</style>

文件查看器组件

<template>
  <div id="fileViewerComponent" class="inline-flex items-center p-2 rounded border-2 border-yellow-500 m-1">
      <h3>Input:</h3>
    <div id="view">
        {{ input }}
    </div>
  </div>
</template>

<script>
import {reactive} from 'vue';
export default {
  name: 'FileViewerComponent',
  emits: ['inFocus', 'submit', 'change'],
  props: {
    input: {
      type: String,
      required: false,
    }, 
  },
  methods : {

  },
  setup(props, {emit}) {
      const file = reactive({
          name: 'Keine Ausgewählt',
          input: Element,
          content: String,
      })

      return {file}
  }
}

</script>

<style scoped>

</style>

【问题讨论】:

  • 我刚刚重建了您的代码示例 [在 Vue SFC 游乐场:tinyurl.com/kscn7fn3 - 它似乎按预期工作?我可以在每个对应的文件输入下方看到文件内容!
  • 感谢您的回复。我发现了问题。 FileInput 的标签指向 id="fileInput" 并使用单击时找到的第一个输入。您可以通过单击第二个 FileInput 旁边的标签在 SFC Playground 中进行测试。

标签: javascript html vue.js vuejs3


【解决方案1】:

最后我得到了一个解决方案。 问题是由指向 id="fileInput" 的 FileInput 标签引起的,它是输入。但是当输入被渲染 2 次时,标签访问第一个找到的 id="fileInput"。

我的解决方案:

FileUploadComponent.vue

我必须获得组件的 ID 并将其用于输入 ID 和标签

<template>
  <div id="fileUploadComponent" class="inline-flex items-center p-2 rounded border-2 border-yellow-500 m-1">
    <input type='file' v-bind:id="id" name="fileInput" @change="fileUploadChange()" ref="fileInput" class="hidden"/>
    <label v-bind:for="id" class="h-10 w-40 rounded text-gray-300 dark:text-gray-400 bg-gray-700 hover:bg-gray-500 text-xs" style="line-height: 2.5rem">
       <span class="block text-center w-full">Datei öffnen</span></label>
     <span id="filenamefield" class="inline-block m-2 text-gray-700 dark:text-gray-300">{{file.name}}</span>
  </div>
</template>

<script>
import {reactive} from 'vue';
export default {
  name: 'FileReaderComponent',
  emits: ['inFocus', 'submit', 'change'],
  props: {
    input: {
      type: String,
      required: false,
    },
    id : {
      type: Number,
      required: false,
    } 
  },
  methods : {
      setContent(content) {
        console.log('FileUpload, set Content', content)
        this.file.content = content;
        this.$emit('change', content);
    },
    fileUploadChange() {
        console.log('fileUploadChange triggered');
        this.file.input = this.$refs.fileInput.files[0];
        this.file.name = this.file.input.name;
        let file = this.file.input;

        let parent = this;
        parent.setContent('Content Loading')
        function onloadevent(evt) {
            parent.setContent(evt.target.result);
        }

        if (file) {
          var reader = new FileReader();
          reader.readAsText(file, "UTF-8");
          reader.onload = function (evt) {
              onloadevent(evt);
          }
          reader.onerror = function () {
              onloadevent('An Error occurred while reading File');
          }
        }
    }
  },
  setup(props, {emit}) {
      const file = reactive({
          name: 'Keine Ausgewählt',
          input: Element,
          content: String,
      })

      return {file}
  }
}

</script>

<style scoped>
    .inputfile {
        width: 0.1px;
        height: 0.1px;
        opacity: 0;
        overflow: hidden;
        position: absolute;
        z-index: -1;
    }

    .inputfile+label {
        font-weight: 700;
        display: inline-block;
    }

    input:checked+svg {
        display: block;
    }
</style>

【讨论】:

    猜你喜欢
    • 2022-01-03
    • 2021-03-28
    • 2019-01-27
    • 2020-03-10
    • 2020-10-03
    • 1970-01-01
    • 2021-05-25
    • 2020-01-07
    • 1970-01-01
    相关资源
    最近更新 更多