如何从 Firebase 存储中删除 Vue.js 组件图像?

Posted

技术标签:

【中文标题】如何从 Firebase 存储中删除 Vue.js 组件图像?【英文标题】:How to delete Vue.js component image from Firebase storage? 【发布时间】:2019-12-15 03:53:59 【问题描述】:

我正在构建一个 Vue.js 组件,该组件可以在 Firebase 上上传和删除图像。到目前为止,我的组件可以将图像上传到数据库和存储。图像只能从数据库中删除,但仍保留在存储中。为了解决这个问题,我尝试使用.then()promise 设置deleteImg()函数来定位存储中的图像以进行删除。文档中的示例 ('https://firebase.google.com/docs/storage/web/delete-files') 设置为针对硬编码图像。如何设置删除功能以删除删除按钮所针对的特定图像?这是我的删除功能:

    deleteImg(img) 
      db.collection("images").doc(img).delete()
      .then(() => 
        var storageRef = firebase.storage().ref();
        var desertRef = storageRef.child('images/Desert.jpg');
        desertRef.delete().then(function() 
          console.log('Document successfully deleted')
        ).catch(function(error) 
          console.log(error)
        );
      )
      .then(() => 
        this.getImages()
      )
    

这是整个组件:

<template>
  <div id="app">
    <v-app-bar color="indigo" dark fixed app>
      <v-toolbar-title>Vue Firebase Image Upload</v-toolbar-title>
    </v-app-bar>
    <v-app id="inspire">
      <v-content>
        <v-container fluid>
          <v-layout align-center justify-center>
            <v-flex xs12 sm8 md4>
              <img :src="imageUrl"  v-if="imageUrl" />
              <v-text-field label="Select Image" @click="pickFile" v-model="imageName"></v-text-field>
              <input type="file" style="display: none" ref="image" accept="image/*" @change="onFilePicked"/>
              <v-btn color="primary" @click="upload">UPLOAD</v-btn>
            </v-flex>
          </v-layout>
          <br />

          <v-layout align-center justify-center>
            <v-flex xs12 sm8 md4>
              <div v-for="img in imgUrls" :key="img.id">
                <br />
                <img :src="img.downloadUrl"  />
                <v-btn @click="deleteImg(img.id)">x</v-btn>
              </div>
            </v-flex>
          </v-layout>
        </v-container>
      </v-content>
    </v-app>
  </div>
</template>

<script>
import firebase from 'firebase'
import  db  from "./main";

export default 
  name: "App",
  data() 
    return 
      photo: null,
      photo_url: null,
      dialog: false,
      imageName: "",
      imageUrl: "",
      imageFile: "",
      imgUrls: []
    ;
  ,
  created() 
    this.getImages();
  ,
  methods: 
    getImages: function() 
      db.collection("images")
        .get()
        .then(snap => 
          const array = [];
          snap.forEach(doc => 
            const data = doc.data()
            array.push(
              id: doc.id,
              ...data
            );
          );
          this.imgUrls = array;
        );
      this.imageName = ""
      this.imageFile = ""
      this.imageUrl = ""
    ,
    pickFile() 
      this.$refs.image.click();
    ,
    onFilePicked(e) 
      const files = e.target.files;
      if (files[0] !== undefined) 
        this.imageName = files[0].name;
        if (this.imageName.lastIndexOf(".") <= 0) 
          return;
        
        const fr = new FileReader();
        fr.readAsDataURL(files[0]);
        fr.addEventListener("load", () => 
          this.imageUrl = fr.result;
          this.imageFile = files[0]; // this is an image file that can be sent to server...
        );
       else 
        this.imageName = "";
        this.imageFile = "";
        this.imageUrl = "";
      
    ,
    upload: function() 
      var storageRef = firebase.storage().ref();
      var mountainsRef = storageRef.child(`images/$this.imageName`);
      mountainsRef.put(this.imageFile).then(snapshot => 
        snapshot.ref.getDownloadURL().then(downloadURL => 
          this.imageUrl = downloadURL;
          const bucketName = "xxx-xxxx-xxxxx.xxxxxxx.xxx";
          const filePath = this.imageName;
          db.collection("images").add(
            downloadURL,
            downloadUrl:
              `https://firebasestorage.googleapis.com/v0/b/$bucketName/o/images` +
              "%2F" +
              `$encodeURIComponent(filePath)?alt=media`,
            originalName: this.imageName,
            timestamp: Date.now()
          );
          this.getImages();
        );
      );
    ,
    deleteImg(img) 
      db.collection("images").doc(img).delete()
      .then(() => 
        var storageRef = firebase.storage().ref();
        var desertRef = storageRef.child('images/Desert.jpg');
        desertRef.delete().then(function() 
          console.log('Document successfully deleted')
        ).catch(function(error) 
          console.log(error)
        );
      )
      .then(() => 
        this.getImages()
      )
    
  ,
  components: 
;
</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>


更新的删除功能

async deleteImg(img) 
  let imgDBRef = await db.collection("images").doc(img).get()
    let imgFileName = imgDBRef.exists ? imgDBRef.data().originalName : null;
    let storageRef = firebase.storage().ref();
    let desertRef = storageRef.child('images/' + imgFileName);
    desertRef.delete()
    db.collection("images").doc(img).delete()
    this.getImages()


【问题讨论】:

【参考方案1】:

这是最终答案:

async deleteImg(img) 
  let imgDBRef = await db.collection("images").doc(img).get()
  let imgFileName = imgDBRef.exists ? imgDBRef.data().originalName : null;
  let storageRef = firebase.storage().ref();
  let desertRef = storageRef.child('images/' + imgFileName);
  await desertRef.delete()
  await db.collection("images").doc(img).delete()
  await this.getImages()

【讨论】:

这里的许多其他答案都具有误导性或已弃用。这个解决方案效果很好!谢谢,@JS_is_awesome18 :)【参考方案2】:

要从存储中删除图片,您需要知道该图片在 Cloud Storage 存储分区中的路径。如果你只有图片的下载地址,你可以通过firebase.storage().refFromUrl(...)获取引用,然后在结果中调用delete()

【讨论】:

您好弗兰克,感谢您的反馈。我了解如何在上传功能的上下文中使用存储路径,但不了解删除功能。你能稍微扩展一下吗?我试图将您所说的应用于我的 deleteImg() 函数,但无济于事。在答案底部查看我的更新功能.. 您的deleteImg 代码乍一看还不错。该代码有什么问题?当您在调试器中单步执行时,哪一行没有按照您的预期执行? 我收到两个错误。先说Error in v-on handler: "[object Object] 。其次是 FirebaseStorageError(见上文) 不能从存储中删除。删除数据库中的文件路径,以及屏幕上的图像。但是图像仍然保留在存储中。我也想删除它。 那么,在调试器中单步调试代码,path 指向什么desertRef?那确实是要删除的图像吗?如果是这样,它是在该行之后进入then() 还是进入catch() 块?【参考方案3】:

我认为您应该尝试将图像文件名保存到数据库,以便能够将其映射到存储项。

从这里添加imageName

storageRef.child(`images/$this.imageName`);

db.collection("images").add(..)函数参数对象:

db.collection("images").add(
            downloadURL,
            originalName: this.imageName,
          );

然后在您的deleteImg 函数中从db.collection("images").doc(img) 文档数据中获取originalName,如下所示:

const imgDBRef = db.collection("images").doc(img).get();
const imgFileName = imgDBRef.exists ? imgDBRef.data().originalName : null;
//... here should be your checks for image name nullable state etc.
const storageRef = firebase.storage().ref();
const desertRef = storageRef.child('images/' + imgFileName);

最好将文件名存储为哈希,而不是真实名称。

【讨论】:

感谢您的回复!我合并了您的答案,但控制台不断返回空值。我将在答案中更新我的删除功能,向您展示我是如何添加它的。有关如何解决此问题的任何建议? 您确定您通过db.collection("images").doc(img) 代码获得了对图像的引用吗?尝试通过console.log 进行检查,然后如果引用不为空,请尝试使用originalName 获取文档值。 我设置了 console.log(imgFileName) 以查看基于 let imgFileName = imgDBRef.exists ? imgDBRef.data().originalName : null; 分配给该 imgFileName 的内容。控制台不断返回 null,这意味着 imgFileName 永远不会真正获得 originalName。是否有另一种方法可以建议您分配对 imgfileName 的引用而不是使用三元语句? 尝试将let imgFileName = imgDBRef.exists ? imgDBRef.data().originalName : null;替换为let imgData = imgDBRef.exists ? imgDBRef.data() : null;,然后检查哪些字段在dataconsole.log(imgData);我们应该检查,imgData确实包含您在上传时设置的一些字段。 再次感谢。 console.log 仍然为此返回 null。

以上是关于如何从 Firebase 存储中删除 Vue.js 组件图像?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Vue.js Firebase UID 删除用户

如何从 Vue Web 应用程序中的 Firebase 存储下载文件?

如何删除用户点击按钮? - Firebase - Vue.js

构建后如何在 Vue.js 项目中存储 Firebase 凭据(env_var)

如何使用 firebase / vue.js 实时删除功能

如何从 Firebase 存储访问图像?