How uploaded file on Firebase storage then store the url inside firestore with vue 3 (composition API)

huangapple go评论165阅读模式
英文:

How uploaded file on Firebase storage then store the url inside firestore with vue 3 (composition API)

问题

我是您的中文翻译,这是您要翻译的代码部分:

im new to firebase and vue 3 and i have prob dealing with upload to storage, i am uploading the file (image) on firebase and want to store it to firestore with all other data from inputs, i was able to save all data from form but cant with the file url, im using this fucntion :

<input @change="uploadTaskPromise" class="file-input" type="file" name="file">

import { getStorage, ref as stRef, uploadBytesResumable, getDownloadURL } from "firebase/storage";

const uploadTaskPromise = (e) => {
  const file = e.target.files[0];
  const storage = getStorage();

  const metadata = {
    contentType: 'image/jpeg'
  };

  const storageRef = stRef(storage, 'products/' + file.name);

  const uploadTask = uploadBytesResumable(storageRef, file, metadata);

  uploadTask.on('state_changed',
    (snapshot) => {

      const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
      console.log('Upload is ' + progress + '% done');
      switch (snapshot.state) {
        case 'paused':
          console.log('Upload is paused');
          break;
        case 'running':
          console.log('Upload is running');
          break;
      }
    },
    (error) => {

      switch (error.code) {
        case 'storage/unauthorized':

          break;
        case 'storage/canceled':

          break;

        // ...

        case 'storage/unknown':

          break;
      }
    },
    () => {

      getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {

        console.log('File available at', downloadURL);

        resolve({ imgUrl: downloadURL });
      });
    });
}
英文:

im new to firebase and vue 3 and i have prob dealing with upload to storage, i am uploading the file (image) on firebase and want to store it to firestore with all other data from inputs, i was able to save all data from form but cant with the file url, im using this fucntion :

&lt;input @change=&quot;uploadTaskPromise&quot; class=&quot;file-input&quot; type=&quot;file&quot; name=&quot;file&quot;&gt;
import { getStorage, ref as stRef, uploadBytesResumable, getDownloadURL } from &quot;firebase/storage&quot;;



const uploadTaskPromise = (e) =&gt; {
  const file = e.target.files[0];
  const storage = getStorage();

  const metadata = {
  contentType: &#39;image/jpeg&#39;
};
  
  const storageRef = stRef(storage, &#39;products/&#39; + file.name);

  const uploadTask = uploadBytesResumable(storageRef, file, metadata);

  
uploadTask.on(&#39;state_changed&#39;,
  (snapshot) =&gt; {
    
    const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
    console.log(&#39;Upload is &#39; + progress + &#39;% done&#39;);
    switch (snapshot.state) {
      case &#39;paused&#39;:
        console.log(&#39;Upload is paused&#39;);
        break;
      case &#39;running&#39;:
        console.log(&#39;Upload is running&#39;);
        break;
    }
  }, 
  (error) =&gt; {
    
    switch (error.code) {
      case &#39;storage/unauthorized&#39;:
        
        break;
      case &#39;storage/canceled&#39;:
        
        break;

      // ...

      case &#39;storage/unknown&#39;:
        
        break;
    }
  }, 
  () =&gt; {
    
    getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) =&gt; {


      console.log(&#39;File available at&#39;, downloadURL);

      resolve({ imgUrl: downloadURL });
    });
  });
}

答案1

得分: 1

以下是您要翻译的内容:

首先,我制作了一个简单的表单...

<template>
  <form action="#" @submit.prevent>
    <div>
      <label for="title">产品标题</label>
      <input v-model="title" type="text" id="title" placeholder="标题" />
    </div>
    <div>
      <label for="price">产品价格</label>
      <input v-model="price" type="number" id="price" min="0" placeholder="0.00" />
    </div>
    <div>
      <label for="file">产品照片</label>
      <input @change="handleFileChange" type="file" id="file" />
    </div>

    <button @click="submitForm">发送</button>
  </form>
</template>

...并且与脚本连接:

<script>
// 这些变量在config.js中设置
import { storage, productsCollectionRef } from '../firebase/config'
// 这是来自Firebase的上传文件所需的函数
import { ref, uploadBytesResumable, getDownloadURL } from 'firebase/storage'
// 这个用于在数据库(Firestore)中创建文档
import { addDoc } from 'firebase/firestore'

export default {
  // 子组件,在主要的App.vue中导入
  name: 'vue-upload',
  data() {
    return {
      title: null,
      price: 0,
      file: null
    }
  },
  methods: {
    handleFileChange(e) {
      // 当选择文件时,更新数据()中的属性
      this.file = e.target.files[0]
    },

    createProduct(data) {
      // 传递到集合和数据的引用
      addDoc(productsCollectionRef, data)
    },

    uploadFile(file) {
      // 从File对象中获取名称和类型属性
      const { name, type } = file
      // 在Firebase中创建文件引用
      const storageRef = ref(storage, 'images/' + name)
      // 上传文件(this.file)到Firebase并附加元数据
      const uploadTask = uploadBytesResumable(storageRef, this.file, {
        contentType: type
      })

      uploadTask.on(
        'state_changed',
        (snapshot) => {
          const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
          console.log('上传进度:' + progress + '%')
        },
        (error) => {
          console.log(error)
        },
        () => {
          // 上传成功。获取URL...
          getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
            // ...创建要写入的数据...
            const data = {
              title: this.title,
              price: this.price,
              url: downloadURL
            }
            // ...并调用一个写入文档到Firestore的函数
            this.createProduct(data)
          })
        }
      )
    },

    submitForm() {
      // 简单的快速验证
      if (this.title && this.price && this.file) {
        this.uploadFile(this.file)
        return
      }

      alert('表单无效')
    }
  }
}
</script>

您可能注意到了import { storage, productsCollectionRef } from '../firebase/config'这一行。
这只是另一个JavaScript文件,我在其中传递了Firebase的配置:

./firebase/config.js

import { initializeApp } from 'firebase/app'

import { getStorage } from 'firebase/storage'
import { getFirestore, collection } from 'firebase/firestore'

const firebaseConfig = {
  apiKey: 'XXXXX',
  authDomain: 'XXXXX',
  projectId: 'XXXXX',
  storageBucket: 'XXXXX',
  messagingSenderId: 'XXXXX',
  appId: 'XXXXX'
}

// 初始化Firebase
const app = initializeApp(firebaseConfig)
const storage = getStorage(app)
const db = getFirestore(app)

// 在我的Firestore数据库中,我创建了一个'products'集合 [截图][1]
const productsCollectionRef = collection(db, 'products')
// 我们需要导出这些设置好的变量以供在其他文件中使用
export { storage, productsCollectionRef }
英文:

First of all - i've made a simple form ...

&lt;template&gt;
  &lt;form action=&quot;#&quot; @submit.prevent&gt;
    &lt;div&gt;
      &lt;label for=&quot;title&quot;&gt;Product title&lt;/label&gt;
      &lt;input v-model=&quot;title&quot; type=&quot;text&quot; id=&quot;title&quot; placeholder=&quot;Title&quot; /&gt;
    &lt;/div&gt;
    &lt;div&gt;
      &lt;label for=&quot;price&quot;&gt;Product price&lt;/label&gt;
      &lt;input v-model=&quot;price&quot; type=&quot;number&quot; id=&quot;price&quot; min=&quot;0&quot; placeholder=&quot;0.00&quot; /&gt;
    &lt;/div&gt;
    &lt;div&gt;
      &lt;label for=&quot;file&quot;&gt;Product photo&lt;/label&gt;
      &lt;input @change=&quot;handleFileChange&quot; type=&quot;file&quot; id=&quot;file&quot; /&gt;
    &lt;/div&gt;

    &lt;button @click=&quot;submitForm&quot;&gt;Send&lt;/button&gt;
  &lt;/form&gt;
&lt;/template&gt;

... and connected it with script

&lt;script&gt;
// this variables setup-ed in config.js
import { storage, productsCollectionRef } from &#39;../firebase/config&#39;
// this function from firebase. need to upload file
import { ref, uploadBytesResumable, getDownloadURL } from &#39;firebase/storage&#39;
// this one for creating document in database (firestore) 
import { addDoc } from &#39;firebase/firestore&#39;

export default {
  // child component, imported in main App.vue
  name: &#39;vue-upload&#39;,
  data() {
    return {
      title: null,
      price: 0,
      file: null
    }
  },
  methods: {
    handleFileChange(e) {
      // when file selected - update property in data()
      this.file = e.target.files[0]
    },

    createProduct(data) {
      // pass a reference to collection and data
      addDoc(productsCollectionRef, data)
    },

    uploadFile(file) {
      // getting name &amp; type properties from File object
      const { name, type } = file
      // create a reference to file in firebase
      const storageRef = ref(storage, &#39;images/&#39; + name)
      // upload file (this.file) to firebase and append metadata
      const uploadTask = uploadBytesResumable(storageRef, this.file, {
        contentType: type
      })

      uploadTask.on(
        &#39;state_changed&#39;,
        (snapshot) =&gt; {
          const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
          console.log(&#39;Upload is &#39; + progress + &#39;% done&#39;)
        },
        (error) =&gt; {
          console.log(error)
        },
        () =&gt; {
          // successful upload. get url ...
          getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) =&gt; {
            // ... make a data to write ...
            const data = {
              title: this.title,
              price: this.price,
              url: downloadURL
            }
            // ... and call a fn that writes a document to a firestore
            this.createProduct(data)
          })
        }
      )
    },

    submitForm() {
      // just quick &amp; simple validation
      if (this.title &amp;&amp; this.price &amp;&amp; this.file) {
        this.uploadFile(this.file)
        return
      }

      alert(&#39;Form invalid&#39;)
    }
  }
}
&lt;/script&gt;

You may notice a import { storage, productsCollectionRef } from &#39;../firebase/config&#39; line.
It's just another one js-file, where i pass configuration for firebase:

./firebase/config.js

import { initializeApp } from &#39;firebase/app&#39;

import { getStorage } from &#39;firebase/storage&#39;
import { getFirestore, collection } from &#39;firebase/firestore&#39;

const firebaseConfig = {
  apiKey: &#39;XXXXX&#39;,
  authDomain: &#39;XXXXX&#39;,
  projectId: &#39;XXXXX&#39;,
  storageBucket: &#39;XXXXX&#39;,
  messagingSenderId: &#39;XXXXX&#39;,
  appId: &#39;XXXXX&#39;
}

// Initialize Firebase
const app = initializeApp(firebaseConfig)
const storage = getStorage(app)
const db = getFirestore(app)

// i&#39;ve made a &#39;products&#39; collection in my firestore database [screenshot][1]
const productsCollectionRef = collection(db, &#39;products&#39;)
// we need export this setuped variables for use in another file
export { storage, productsCollectionRef }

答案2

得分: 0

@bahyllam我没有足够的声望添加评论。在你之前的代码(4月10日5:05)中,你在`this.files`中有一个数组,但是你的`uploadFile(file)`函数接受单个`file`作为参数。所以在这个函数内部,你需要为整个数组做一个循环,分别为每个`file`调用所有的代码(为每个文件获取`name`和`type`,创建`storageRef`和`uploadTask`。但只进行一次写操作:

handleFileChange(e) {
if (e.target.files) {
for (const file of e.target.files) {
this.files.push(file)
}
}
}

uploadFile() {
const urls = []
const promises = []

this.files.forEach((file) => {
// getting name & type properties from each File object
const { name, type } = file
// create a reference to each file in firebase
const storageRef = ref(storage, 'images/' + name)
// upload each file to firebase and append metadata
const uploadTask = uploadBytesResumable(storageRef, file, {
contentType: type
})

// create task with promises. this will help us to expect the result correctly
const promise = new Promise((resolve, reject) => {
  uploadTask.on(
    'state_changed',
    (snapshot) => {
      const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
      console.log('Upload is ' + progress + '% done')
    },
    (error) => {
      console.log(error)
      reject(error)
    },
    async () => {
      // wait for URL from getDownloadURL 
      const url = await getDownloadURL(uploadTask.snapshot.ref)
      urls.push(url)
      resolve(url)
    }
  )
})

// add task to "waitlist"
promises.push(promise)

})

// when all "waitlist" resolve ...
Promise.all(promises).then(() => {
// ... make a data to write ...
const data = {
title: this.title,
price: this.price,
// url: [Array]
url: urls
}
// ... and call a fn that writes a document to a firestore
this.createProduct(data)
})
}


<details>
<summary>英文:</summary>

@bahyllam i don&#39;t have enough reputation to add a comment.

in your previous code (Apr 10 at 5:05), you have an array in `this.files`, but your `uploadFile(file)` function takes a single `file` as an argument.
So inside this function you need to make a loop for the whole array and call all the code for each `file` separately (get a `name` &amp; `type` for each file, make `storageRef` and `uploadTask`. BUT only once make a write operation:

    handleFileChange(e) {
        if (e.target.files) {
            for (const file of e.target.files) {
                this.files.push(file)
            }
        }
    }

    uploadFile() {
      const urls = []
      const promises = []
    
      this.files.forEach((file) =&gt; {
        // getting name &amp; type properties from each File object
        const { name, type } = file
        // create a reference to each file in firebase
        const storageRef = ref(storage, &#39;images/&#39; + name)
        // upload each file to firebase and append metadata
        const uploadTask = uploadBytesResumable(storageRef, file, {
          contentType: type
        })
    
        // create task with promises. this will help us to expect the result correctly
        const promise = new Promise((resolve, reject) =&gt; {
          uploadTask.on(
            &#39;state_changed&#39;,
            (snapshot) =&gt; {
              const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
              console.log(&#39;Upload is &#39; + progress + &#39;% done&#39;)
            },
            (error) =&gt; {
              console.log(error)
              reject(error)
            },
            async () =&gt; {
              // wait for URL from getDownloadURL 
              const url = await getDownloadURL(uploadTask.snapshot.ref)
              urls.push(url)
              resolve(url)
            }
          )
        })
    
        // add task to &quot;waitlist&quot;
        promises.push(promise)
      })
    
      // when all &quot;waitlist&quot; resolve ...
      Promise.all(promises).then(() =&gt; {
        // ... make a data to write ...
        const data = {
          title: this.title,
          price: this.price,
          // url: [Array]
          url: urls
        }
        // ... and call a fn that writes a document to a firestore
        this.createProduct(data)
      })
    }

</details>



huangapple
  • 本文由 发表于 2023年4月4日 10:53:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/75925173.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定