Vue组件封装上传图片和视频的示例代码

首先下载依赖:

cnpm i -S vue-uuid ali-oss

图片和视频字段都是数组类型,保证可以上传多个文件。

UploadImageVideo:

<!--UploadImageVideo 分片上传    -->
<template>
  <div class="UploadImageVideo">
    <el-upload
      action
      :on-change="handleChange"
      :on-remove="handleRemove"
      :limit="limitFileNumber"
      :on-exceed="handleExceed"
      :file-list="_fileList"
      :http-request="handleHttpRequest"
      :before-upload="handleBeforeUpload"
      :multiple="isMultiple"
    >
      <el-button slot="trigger" size="small" type="primary">选择文件</el-button>
      <div slot="tip" class="el-upload__tip">{{ tip }}</div>
    </el-upload>

    <el-dialog
      title="上传进度"
      :visible.sync="dialogTableVisible"
      :close-on-click-modal="false"
      :modal-append-to-body="false"
    >
      <el-progress :text-inside="true" :stroke-width="26" :percentage="percentage"></el-progress>
    </el-dialog>
  </div>
</template>

<script>
import { uuid } from "vue-uuid";
const OSS = require("ali-oss");

export default {
  name: "",
  components: {},
  props: {
    region: {
      type: String,
      default: "oss-cn-chengdu"
    },
    accessKeyId: {
      type: String,
      default: "xxx"
    },
    accessKeySecret: {
      type: String,
      default: "xxx"
    },
    //存储位置
    bucket: {
      type: String,
      required: true
    },
    currentUrls: {
      type: Array,
      default: () => [],
      required: true
    },
    //限制上传文件数量
    limitFileNumber: {
      type: Number,
      default: 1
    },
    //是否支持多选
    isMultiple: {
      type: Boolean,
      default: false
    },
    //文件格式
    fileType: {
      type: String,
      default: ""
    },
    //提示
    tip: {
      type: String
    }
  },
  data() {
    return {
      client: new OSS({
        region: this.region,
        accessKeyId: this.accessKeyId,
        accessKeySecret: this.accessKeySecret,
        bucket: this.bucket
      }),
      percentage: 0,
      dialogTableVisible: false,
      fileList: []
    };
  },
  computed: {
    //注意:计算属性里面慎用console.log()来打印,因为有可能打印的变量是依赖某个属性而出现该计算属性重复调用!!!!!!
    _fileList() {
      const arr = [];
      //一定要this.currentUrls判断一下是否非空,否则要报错
      if (this.currentUrls.length !== 0) {
        for (const item of this.currentUrls) {
          let { pathname } = new URL(item);
          arr.push({ name: decodeURIComponent(pathname), url: item });
        }
      }

      this.fileList = arr; //这行代码很重要!!
      return arr;
    }
  },
  created() {},
  mounted() {},
  methods: {
    handleChange(file, fileList) {
      this.fileList = fileList;
    },
    handleRemove(file, fileList) {
      this.fileList = fileList;
    },
    handleExceed(files, fileList) {
      this.$message.warning(
        `当前限制选择 ${this.limitFileNumber} 个文件,本次选择了 ${
          files.length
        } 个文件,共选择了 ${files.length + fileList.length} 个文件`
      );
    },

    //注意:为了让自定义上传handleHttpRequest生效,需满足:
    // 1、设置:auto-upload='true'或者不写这个属性,因为它默认为true  2、设置action='#'或者直接写action
    handleHttpRequest(file) {
      //虽然没有内容,但是这个函数不能少!
    },
    //注意:自定义上传handleHttpRequest必须要生效,才会触发before-upload钩子函数
    handleBeforeUpload(file) {
      if (this.fileType == "image") {
        let { type, size, name } = file;
        let isJPEG = type === "image/jpeg";
        let isJPG = type === "image/jpg";
        let isPNG = type === "image/png";
        let isLt5M = size / 1024 / 1024 < 5;
        if (!isJPEG && !isJPG && !isPNG) {
          this.$message.error("上传图片只能是 JPEG/JPG/PNG  格式!");
          return false;
        }
        if (!isLt5M) {
          this.$message.error("单张图片大小不能超过 5MB!");
          return false;
        }
      }
      if (this.fileType == "video") {
        let { type, size, name } = file;
        let isMP4 = type === "video/mp4";
        let isLt50M = size / 1024 / 1024 < 50;
        if (!isMP4) {
          this.$message.error("上传视频只能是 MP4  格式!");
          return false;
        }
        if (!isLt50M) {
          this.$message.error("单个视频大小不能超过 50MB!");
          return false;
        }
      }
    },
    // 分片上传数据,可展示进度条。上传重命名后的文件到alioss, 并返回单个文件url字符串。可支持中文文件名
    async UploadImageVideo(filename, file) {
      let newFileName =
        filename.split(".")[0] + "-" + uuid.v1() + "." + filename.split(".")[1];
      let that = this;
      that.dialogTableVisible = true;

      let {
        res: { requestUrls }
      } = await this.client.multipartUpload(newFileName, file, {
        progress: function(p, checkpoint) {
          that.percentage = parseFloat((p * 100).toFixed(2));
        }
      });
      if (that.percentage == 100) {
        that.dialogTableVisible = false;
      }
      let { origin, pathname } = new URL(requestUrls[0]);
      return origin + decodeURIComponent(pathname);
    },
    //批量上传文件。返回成功上传的url数组
    async addFiles() {
      let urls = [];
      if (this.fileList.length !== 0) {
        for (const item of this.fileList) {
          let { name, raw } = item;
          let pathname = await this.UploadImageVideo(name, raw);
          urls.push(pathname);
        }
      }
      return urls;
    },
    //更新文件数据。上传新数据到服务器,并删除服务器中的旧数据,返回更新后的url数组
    async UpdateFiles() {
      let arr_newUploaded = []; //新上传的图片url。
      let arr_original = []; //原有的图片url。不用删除
      let arr_delete = []; //需要删除的图片url。
      if (this.fileList.length !== 0) {
        for (const { raw, name, url } of this.fileList) {
          //注意:这里一定要判断raw是否存在。存在,则表示是新上传的;不存在,则表示是原有的
          if (raw) {
            let pathname = await this.UploadImageVideo(name, raw);
            arr_newUploaded.push(pathname);
          }
          if (this.currentUrls.includes(url)) {
            arr_original.push(url);
          }
        }
      }

      for (const element of this.currentUrls) {
        if (!arr_original.includes(element)) {
          arr_delete.push(element);
        }
      }
      await this.deleteMultiFiles(arr_delete);

      return [...arr_original, ...arr_newUploaded];
    },
    //批量删除服务器中的文件。参数:待删除到服务器文件url数组。
    async deleteMultiFiles(urls = []) {
      let arr_pathname = [];
      if (urls.length !== 0) {
        for (const item of urls) {
          //不要用let url=require("url");url.parse();已失效。要用new URL()
          let { pathname } = new URL(item);
          // decodeURIComponent()函数将中文乱码转为中文
          arr_pathname.push(decodeURIComponent(pathname));
        }
        //删除服务器中的图片
        await this.client.deleteMulti(arr_pathname);
      }
    }
  },
  watch: {}
};
</script>

<style lang="scss" scoped>
.UploadImageVideo {
  /*去除upload组件过渡效果*/
  ::v-deep .el-upload-list__item {
    transition: none !important;
  }
}
</style>

使用:

<UploadImageVideo
  ref="ref_UploadImageVideo"
  bucket="xxx"
  :currentUrls="formData.imgurl"
  :limitFileNumber="3"
  tip="1、最多上传3张照片; 2、上传图片只能是 JPEG/JPG/PNG 格式; 3、单张图片大小不能超过 5MB!"
  fileType="image"
  :isMultiple="true"
></UploadImageVideo>
  • fileType可选。默认不写,表示图片、视频都可上传。fileType="image"表示只能上传图片。fileType="video"表示只能上传视频
  • bucket必选。
  • isMultiple可选。默认为false
  • currentUrls必选。当前目前已有的文件服务器url数组。通常新增文件时,传入的currentUrls为空数组[];更新文件时,传入到currentUrls为非空数组
  • tip可选。提示内容

提供的方法:(当前组件中所有的上传都是批量上传,且为分片上传,以展示上传进度条)

  1. UpdateFiles()。更新文件数据。上传新数据到服务器,并删除服务器中的旧数据,返回更新后的url数组
  2. addFiles()。批量上传文件。返回成功上传的url数组
  3. deleteMultiFiles(urls = [])。批量删除服务器中的文件。参数:待删除到服务器文件url数组。
  4. UploadImageVideo(filename, file)。分片上传数据,可展示进度条。上传重命名后的文件到alioss, 并返回单个文件url字符串。可支持中文文件名

调用组件中的方法:例如可通过 let urls = await this.$refs["ref_UploadImageVideo"].addFiles();调用批量上传图片或视频的方法

例1:

<!--userManage-->
<template>
  <div class="userManage">
    <el-card>
      <div style="margin-bottom: 10px">
        <el-input
          v-model="searchName"
          clearable
          placeholder="输入用户名称搜索"
          style="width: 200px; margin-right: 10px"
        />
        <el-button
          sizi="mini"
          type="success"
          icon="el-icon-search"
          @click="searchUser(searchName)"
        >搜索</el-button>
        <el-button
          sizi="mini"
          type="warning"
          icon="el-icon-refresh-left"
          @click="searchName = ''"
        >重置</el-button>
        <el-button sizi="mini" @click="handleAdd()" type="primary" icon="el-icon-plus">新增</el-button>
        <el-button @click="getUserList()" sizi="mini" icon="el-icon-refresh" style="float: right">刷新</el-button>
      </div>
      <el-table :data="tableData" border v-loading="isLoading">
        <el-table-column label="用户名" prop="username" align="center" width="150px"></el-table-column>
        <el-table-column label="密码" prop="password" align="center"></el-table-column>
        <el-table-column label="图片" align="center">
          <template slot-scope="scope">
            <div
              style="
                display: flex;
                justify-content: space-around;
                flex-flow: row wrap;
              "
            >
              <el-image
                style="width: 50px; height: 50px"
                v-for="(item, index) in scope.row.imgurl"
                :key="index"
                :src="item"
                :preview-src-list="scope.row.imgurl"
              ></el-image>
              <!-- <a :href="scope.row.imgurl" rel="external nofollow"  target="_blank">{{scope.row.imgurl}}</a> -->
            </div>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center">
          <template slot-scope="scope">
            <el-button size="mini" @click="showEditDialog(scope.row)">
              <i class="el-icon-edit" /> 编辑
            </el-button>
            <el-button size="mini" type="danger" @click="handleDelete(scope.row)">
              <i class="el-icon-delete" /> 删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <UserManageDialog :dialog="dialog" :formData="formData" @addUser="addUser" @editUser="editUser"></UserManageDialog>
  </div>
</template>

<script>
import UserManageDialog from "./userManageDialog.vue";
import { client_alioss, deleteMultiFiles } from "@/utils/alioss.js";

import {
  addUser,
  getUserList,
  editUser,
  deleteUser,
  searchUser
} from "@/api/userManage/index";
export default {
  name: "userManage",
  components: { UserManageDialog },
  data() {
    return {
      searchName: "",
      isLoading: false,
      dialog: {
        show: false,
        title: ""
      },
      formData: {},
      tableData: [
        {
          _id: "",
          username: "admin",
          password: "123",
          imgurl: []
        }
      ],
      currentImgs: []
    };
  },
  props: {},
  created() {},
  mounted() {
    this.getUserList();
  },
  computed: {},
  methods: {
    //获取用户列表
    async getUserList() {
      this.isLoading = true;
      let { data } = await getUserList();
      this.tableData = data.data;
      this.isLoading = false;
    },

    //打开新增用户窗口
    handleAdd() {
      this.dialog = {
        show: true,
        title: "新增用户",
        option: "add"
      };
      this.formData = {
        username: "",
        password: "",
        imgurl: []
      };
    },
    //打开编辑用户窗口
    showEditDialog(row) {
      this.currentImgs = row.imgurl;

      this.dialog = {
        show: true,
        title: "编辑用户",
        option: "edit"
      };
      this.formData = {
        _id: row._id,
        username: row.username,
        password: row.password,
        imgurl: row.imgurl
      };
    },
    //新增用户
    async addUser(urls) {
      this.formData.imgurl = urls;

      await addUser(this.formData);
      this.dialog.show = false;
      this.$notify({
        title: "成功",
        message: "新增用户成功!",
        type: "success"
      });
      this.getUserList();
    },
    //编辑用户
    async editUser(urls) {
      this.formData.imgurl = urls;

      await editUser(this.formData, this.formData._id); //更新数据库,尤其是图片url

      this.dialog.show = false;
      this.$notify({
        title: "成功",
        message: "编辑用户成功!",
        type: "success"
      });
      this.getUserList();
    },
    //删除用户
    handleDelete({ _id }) {
      this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(async () => {
          this.$message({
            type: "success",
            message: "删除成功!",
            showClose: true
          });
          let {
            data: { imgurl }
          } = await deleteUser(_id);

          //删除服务器中的文件。传入待删除的url数组
          await deleteMultiFiles(imgurl);

          this.getUserList();
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除",
            showClose: true
          });
        });
    },
    //根据用户名查询
    async searchUser(searchName) {
      this.isLoading = true;
      let { data } = await searchUser({
        searchName
      });
      this.tableData = data.data;
      this.isLoading = false;
    }
  },
  watch: {}
};
</script>

<style lang="scss" scoped>
.userManage {
}
</style>

<!--userManageDialog   -->
<template>
  <div class="userManageDialog">
    <el-dialog :title="dialog.title" width="45%" :visible.sync="dialog.show" v-if="dialog.show">
      <el-form ref="ref_form_userManage" :model="formData" :rules="rules" label-width="100px">
        <el-form-item label="用户名" prop="username">
          <el-input v-model="formData.username" autocomplete="off" style="width: 90%"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input v-model="formData.password" autocomplete="off" style="width: 90%"></el-input>
        </el-form-item>
        <el-form-item label="图片" prop="imgurl">
          <!-- fileType属性不写的话,表示图片、视频都可上传。fileType="image"表示只能上传图片。fileType="video"表示只能上传视频 -->
          <UploadImageVideo
            ref="ref_UploadImageVideo"
            bucket="bucket-lijiang-test"
            :currentUrls="formData.imgurl"
            :limitFileNumber="3"
            tip="1、最多上传3张照片; 2、上传图片只能是 JPEG/JPG/PNG 格式; 3、单张图片大小不能超过 5MB!"
            fileType="image"
            :isMultiple="true"
          ></UploadImageVideo>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialog.show = false">取 消</el-button>
        <el-button
          v-if="dialog.option == 'add'"
          @click="addUser('ref_form_userManage')"
          type="primary"
        >确 定</el-button>
        <el-button
          v-if="dialog.option == 'edit'"
          @click="editUser('ref_form_userManage')"
          type="primary"
        >确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import UploadImageVideo from "@/components/UploadImageVideo";

export default {
  name: "userManageDialog",
  components: { UploadImageVideo },
  props: ["dialog", "formData"],
  data() {
    return {
      fileList: [],
      rules: {
        username: [
          { required: true, message: "请输入用户名称", trigger: "blur" }
        ]
      }
    };
  },
  created() {},
  mounted() {},
  computed: {},
  methods: {
    addUser(formName) {
      this.$refs[formName].validate(async valid => {
        if (valid) {
          let urls = await this.$refs["ref_UploadImageVideo"].addFiles();
          this.$emit("addUser", urls);
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    editUser(formName) {
      this.$refs[formName].validate(async valid => {
        if (valid) {
          let urls = await this.$refs["ref_UploadImageVideo"].UpdateFiles();

          this.$emit("editUser", urls);
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    }
  },
  watch: {}
};
</script>
<style lang="scss" scoped>
</style>

import { uuid } from 'vue-uuid';
const OSS = require("ali-oss");

let client = new OSS({
    region: "oss-cn-chengdu",
    accessKeyId: "LTAI5tQPHvixV8aakp1vg8Jr",
    accessKeySecret: "xYyToToPe8UFQMdt4hpTUS4PNxzl9S",
    bucket: "bucket-lijiang-test",

});

export const client_alioss = client;

//删除文件数组
export async function deleteMultiFiles(urls = []) {
    let arr_pathname = [];
    if (urls.length !== 0) {
        for (const item of urls) {
            //不要用let url=require("url");url.parse();已失效。要用new URL()
            let { pathname } = new URL(item);
            // decodeURIComponent()函数将中文乱码转为中文
            arr_pathname.push(decodeURIComponent(pathname));
        }
        await client.deleteMulti(arr_pathname);
    }
}

import request from '@/utils/request'
//  获取用户列表
export function getUserList() {
    return request({
        url: '/api/userManage',
        method: 'get'
    })
}

//  新增用户
export function addUser(data) {
    return request({
        url: '/api/userManage',
        method: 'post',
        data
    })
}

//  编辑用户
export function editUser(data, _id) {
    return request({
        url: `/api/userManage/${_id}`,
        method: 'put',
        data
    })
}

//  删除用户
export function deleteUser(_id) {
    return request({
        url: `/api/userManage/${_id}`,
        method: 'delete'
    })
}

//  根据关键字查询
export function searchUser(data) {
    return request({
        url: `/api/userManage/search`,
        method: 'get',
        params: data
    })
}

const router = require('koa-router')()

const User = require("../models/User"); //引入模块模型
router.prefix('/userManage')

//获取用户列表
router.get('/', async (ctx, next) => {
    let data = await User.find({})
    ctx.body = {
        code: 200,
        message: "请求成功",
        data,
    }
})
//新增用户
router.post('/', async (ctx, next) => {
    let { username, password, imgurl } = ctx.request.body;
    await User.create({ username, password, imgurl })
    ctx.body = { code: 200, message: "新增成功" }
})
//编辑用户
router.put('/:_id', async (ctx, next) => {
    let { username, password, imgurl } = ctx.request.body;
    let { _id } = ctx.params

    await User.findByIdAndUpdate(_id, { username, password, imgurl })
    ctx.body = { code: 200, message: "编辑成功" }
})
//删除用户
router.delete('/:_id', async (ctx, next) => {
    let { _id } = ctx.params;
    let { imgurl } = await User.findByIdAndDelete(_id)
    ctx.body = { code: 200, message: "删除成功", imgurl }

})

//根据关键字查询用户。模糊查询

router.get('/search', async (ctx, next) => {
    let { searchName } = ctx.request.query;

    let data = await User.find({ username: { $regex: searchName } })
    ctx.body = { code: 200, message: "查询成功", data }
})
module.exports = router

到此这篇关于Vue封装上传图片和视频的组件的文章就介绍到这了,更多相关vue组件封装内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于vue-upload-component封装一个图片上传组件的示例

    需求分析 业务要求,需要一个图片上传控件,需满足 多图上传 点击预览 图片前端压缩 支持初始化数据 相关功能及资源分析 基本功能 先到https://www.npmjs.com/search?q=vue+upload上搜索有关上传的控件,没有完全满足需求的组件,过滤后找到 vue-upload-component 组件,功能基本都有,自定义也比较灵活,就以以此进行二次开发. 预览 因为项目是基于 vant 做的,本身就提供了 ImagePreview 的预览组件,使用起来也简单,如果业务需求需要

  • Vue封装一个简单轻量的上传文件组件的示例

    一.之前遇到的一些问题 项目中多出有上传文件的需求,使用现有的UI框架实现的过程中,不知道什么原因,总会有一些莫名其妙的bug.比如用某上传组件,明明注明(:multiple="false"),可实际上还是能多选,上传的时候依然发送了多个文件:又比如只要加上了(:file-list="fileList")属性,希望能手动控制上传列表的时候,上传事件this.refs.[upload(组件ref)].submit()就不起作用了,传不了.总之,懒得再看它怎么实现了,我

  • vue-cropper插件实现图片截取上传组件封装

    基于vue-cropper插件实现图片截取上传组件封装的具体代码,供大家参考,具体内容如下 需求场景: 后台开发需要上传图片并进行相应比例尺寸图片的截取,本组件开发采用Ant Design Vue组件库搭配vue-cropper插件进行封装 实现如下 html <template> <div> <a-upload name="avatar" list-type="picture-card" class="avatar-uplo

  • Vue开发之封装上传文件组件与用法示例

    本文实例讲述了Vue开发之封装上传文件组件与用法.分享给大家供大家参考,具体如下: 使用elementui的 el-upload插件实现图片上传组件 每个项目存在一定的特殊性,所以数据的处理会不同 pictureupload.vue: <template> <div class="pictureupload"> <el-upload :action="baseUrl + '/api/public/image'" list-type=&q

  • Vue组件封装上传图片和视频的示例代码

    首先下载依赖: cnpm i -S vue-uuid ali-oss 图片和视频字段都是数组类型,保证可以上传多个文件. UploadImageVideo: <!--UploadImageVideo 分片上传 --> <template> <div class="UploadImageVideo"> <el-upload action :on-change="handleChange" :on-remove="ha

  • vue组件中使用iframe元素的示例代码

    本文介绍了vue组件中使用iframe元素的示例代码,分享给大家,具体如下: 需要在本页面中展示vue组件中的超链接,地址栏不改变的方法: <template> <div class="accept-container"> <div class="go-back" v-show="goBackState" @click="goBack">GoBack</div> <ul&g

  • vue组件挂载到全局方法的示例代码

    在最近的项目中,使用了bootstrap-vue来开发,然而在实际的开发过程中却发现这个UI提供的组件并不能打到我们预期的效果,像alert.modal等组件每个页面引入就得重复引入,并不像element那样可以通过this.$xxx来调用,那么问题来了,如何通过this.$xxx来调用起我们定义的组件或对我们所使用的UI框架的组件呢. 以bootstrap-vue中的Alert组件为例,分一下几步进行: 1.定义一个vue文件实现对原组件的再次封装 main.vue <template> &

  • vue组件封装实现抽奖随机数

    本文实例为大家分享了vue组件封装实现抽奖随机数的具体代码,供大家参考,具体内容如下 一.子组件 <template>     <div>      <slot></slot>     </div> </template>     <script>      export default {          name:'countUp',          props:{              lastSymbol:

  • Vue组件实现景深卡片轮播示例

    目录 前言 需求拆解 开发思路(vue2) 开发过程 后记 前言 朋友的朋友做了个首页,首页用到一个卡片轮播,大概就是这个样子的: 第一版他们是开发出来了,但是各种bug,希望我帮忙改一下. 看完代码以后,发现他们整合了一个缝合怪出来,各个楼层都是从其他地方 CV 过来的,而且各个楼层引用了 n 多个js 和 css 文件,看了一下效果以后,觉得改他的东西确实比重新开发一个要麻烦的多得多,所以就重新写了一下. 在此记录一下,以便于后续复用. 需求拆解 初始化渲染5个容器,用来承载图片和标题,按照

  • Vue 组件封装 并使用 NPM 发布的教程

    正文开始 Vue 开发插件 我们可以先查看Vue的插件的开发规范 我们开发的之后期望的结果是支持 import.require 或者直接使用 script 标签的形式引入,就像这样: ps: 这里注意一下包的名字前缀是 unisoft ,组件的名字前缀是 uni import UniSoftUI from 'unisoft-ui'; // 或者 const CustomUI = require('unisoft-ui'); // 或者 <script src="...">&

  • Vue组件封装之input输入框实战记录

    目录 实战目的 实战效果 核心思想 一 格式规范 二 给父组件传递value值 三 错误提示 四 格式检验 五 多个input框的检验 写在最后 实战目的 封装一个自定义的input组件,只适用于 input元素type属性为text或password. 实战效果 核心思想 准备: 需要两个文件,分别为 register.vue(父组件), input.vue(子组件) register.vue 引入 input.vue import inputstyle from '@/components/

  • Vue实现悬浮框自由移动+录音功能的示例代码

    目录 效果如下 主要功能 实现 1.封装第一个漂浮组件FloatBall.vue 2.封装第二个组件录音组件Audio.vue 3.recorder.js 效果如下 主要功能 1.一个漂浮的球,在全屏幕中自由移动遇到边边角角自动改变方向 ,自带动画效果 2.录音功能,可以录制用户的声音,可以下载为任意格式的音频文件到本地,也可以通过二进制流发给后端 由于后端要声音文件格式wav或者pcm,采样率16000,所以我改了配置文件,稍后我会介绍在哪里改,改什么什么样都是可以的. 注:代码我已经封装成组

  • vue 2.0 购物车小球抛物线的示例代码

    本文介绍了vue 2.0 购物车小球抛物线的示例代码,分享给大家,具体如下: 备注:此项目模仿 饿了吗.我用的是最新的Vue, 视频上的一些写法已经被废弃了. 布局代码 <div class="ball-container"> <transition name="drop" v-for="ball in balls" @before-enter="beforeDrop" @enter="droppi

  • Vue的props父传子的示例代码

    废话不多少,父传子做一个比喻 首页想加一个图片,但又不想每次都用img而且又让img做css和动画事件.此时最简单的方法做一个页面封装,然后起一个名字让首页自己获取,放一个地址就行!其他什么都不用管. 步骤如下: 第一步:创建一个组件,相当于创意文件夹,专门存小东西以后经常用 <template> <div> <img src="./xxx.xx" alt=""> </div> </template> &l

随机推荐