一五六、Node+Vue 使用七牛上传图片,并配置个人域名

1. 七牛云ak/sk获取

  1. 点击注册🔗开通七牛开发者帐号
  2. 如果已有账号,直接登录七牛开发者后台,点击这里🔗查看 Access Key 和 Secret Key

2. Node.js获取七牛token

安装qiniu

js 复制代码
npm install qiniu

创建空间

Node获取token

js 复制代码
const qiniu = require('qiniu');
const ACCESS_KEY = 'xxx';
const SECRET_KEY = 'xxx';
const mac = new qiniu.auth.digest.Mac(ACCESS_KEY, SECRET_KEY);

const {Auth} = require('@middlewares/auth');
const AUTH_ADMIN = 16;

const {Resolve} = require('@lib/helper');
const res = new Resolve();

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

const router = new Router({
    prefix: '/api/v1'
});

// 获取token
router.post('/upload/token', new Auth(AUTH_ADMIN).m, async ctx => {
    const options = {
        scope: 'xxx', //你的存储空间名称
        expires: 7200
    };
    const putPolicy = new qiniu.rs.PutPolicy(options);
    ctx.response.status = 200;
    const data = {
        token: putPolicy.uploadToken(mac)
    };
    ctx.body = res.json(data);
});

module.exports = router;

3. Vue获取token并上传图片

获取token

js 复制代码
//src/api/upload.js
import request from '@/utils/request';

// 获取上传图片token
export function getToken(params) {
    return request({
        url: '/upload/token',
        method: 'post',
        params
    });
}
js 复制代码
<template>
  <section class="wrap">
    <el-form
      ref="ruleForm"
      :model="ruleForm"
      :rules="rules"
      label-width="120px"
      class="demo-ruleForm"
    >
      <el-form-item label="标题" prop="title">
        <el-input v-model="ruleForm.title" />
      </el-form-item>
      <el-form-item label="描述" prop="description">
        <el-input v-model="ruleForm.description" />
      </el-form-item>
      <el-form-item label="SEO关键字" prop="seo_keyword">
        <el-input v-model="ruleForm.seo_keyword" />
      </el-form-item>
      <el-form-item label="图片" prop="img_url">
        <el-upload
          class="avatar-uploader"
          action="https://upload-z0.qiniup.com/"
          :show-file-list="false"
          :data="{ token }"
          :on-success="handleUploadSuccess"
        >
          <img
            v-if="ruleForm.img_url"
            width="80"
            height="80"
            :src="ruleForm.img_url"
            class="avatar"
          />
          <i v-else class="el-icon-plus avatar-uploader-icon" />
        </el-upload>
      </el-form-item>
      <el-form-item label="展示" prop="status">
        <el-radio-group v-model="ruleForm.status">
          <el-radio :label="1">显示</el-radio>
          <el-radio :label="0">隐藏</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="分类" prop="category_id">
        <el-select v-model="ruleForm.category_id" placeholder="请选择分类">
          <el-option
            v-for="item in categoryList"
            :key="item.id"
            :label="item.name"
            :value="item.id"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="排序" prop="sort_order">
        <el-input v-model="ruleForm.sort_order" />
      </el-form-item>
      <el-form-item label="内容" prop="content">
        <mavon-editor
          ref="md"
          v-model="ruleForm.content"
          code-style="atom-one-dark"
          @imgAdd="$imgAdd"
          @imgDel="$imgDel"
        />
      </el-form-item>

      <el-form-item>
        <el-button @click="resetForm('ruleForm')">重置</el-button>
        <el-button type="primary" @click="submitForm('ruleForm')">
          立即创建
        </el-button>
      </el-form-item>
    </el-form>
  </section>
</template>

<script>
import { mapState } from "vuex";
import { create } from "@/api/article";
import { list } from "@/api/category";
import { getToken } from "@/api/upload";
import axios from "axios";

export default {
  name: "CategoryCreate",
  data() {
    return {
      token: "",
      categoryList: [],
      ruleForm: {
        title: "",
        description: "",
        img_url: "",
        seo_keyword: "",
        status: 1,
        sort_order: 1,
        admin_id: "",
        category_id: "",
        content: "",
      },
      rules: {
        title: [{ required: true, message: "请输入文章标题", trigger: "blur" }],
        description: [
          { required: true, message: "请输入文章描述", trigger: "blur" },
        ],
        img_url: [
          { required: true, message: "请输入图片链接", trigger: "blur" },
        ],
        seo_keyword: [
          { required: true, message: "请输入 SEO 关键字", trigger: "blur" },
        ],
        status: [
          { required: true, message: "请输入展示状态", trigger: "blur" },
        ],
        sort_order: [
          { required: true, message: "请输入文章排序", trigger: "blur" },
        ],
        category_id: [
          { required: true, message: "请选择分类", trigger: "blur" },
        ],
        content: [
          { required: true, message: "请输入文章内容", trigger: "blur" },
        ],
      },
    };
  },
  computed: {
    ...mapState({
      adminInfo: (state) => state.admin.adminInfo,
    }),
  },
  mounted() {
    this.$axios = axios.create({ withCredentials: false });
    this.getUploadToken();
    this.getCategoryList();
  },
  methods: {
    // 获取上传token
    async getUploadToken() {
      try {
        const res = await getToken();
        this.token = res.data.token;
      } catch (err) {
        console.log(err);
      }
    },
    // 上传图片成功回调
    handleUploadSuccess(file) {
      console.log("🚀 > handleUploadSuccess > file", file);
      this.ruleForm.img_url = `http://cdn.at-will.cn/${file.key}`;
      this.$message.success("上传成功!");
    },
    // 编辑器删除图片回调
    $imgDel(pos, $file) {
      console.log(pos, $file);
    },
    // 编辑器新增上传图片回调
    $imgAdd(pos, $file) {
      const loading = this.$loading({
        lock: true,
        text: "Loading",
        spinner: "el-icon-loading",
        background: "rgba(0, 0, 0, 0.7)",
      });

      // 第一步.将图片上传到服务器.
      const formdata = new FormData();
      formdata.append("file", $file);
      formdata.append("token", this.token);
      this.$axios({
        url: "https://upload-z0.qiniup.com/",
        method: "post",
        data: formdata,
        headers: { "Content-Type": "multipart/form-data" },
      })
        .then((res) => {
          const img_url = `http://cdn.at-will.cn/${res.data.key}`;
          this.$refs.md.$img2Url(pos, img_url);
          loading.close();
        })
        .catch((err) => {
          console.log(err);
          loading.close();
        });
    },
    // 获取分类列表
    async getCategoryList() {
      try {
        this.listLoading = true;
        const res = await list();
        this.categoryList = res.data.data;
      } catch (err) {
        console.log(err);
      } finally {
        this.listLoading = false;
      }
    },
    // 提交表单
    submitForm(formName) {
      if (this.adminInfo) {
        this.ruleForm.admin_id = this.adminInfo.id;
      }

      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          this.createArticle();
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    // 重置表单
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
    // 创建文章
    async createArticle() {
      try {
        const res = await create(this.ruleForm);
        if (res.code === 200) {
          this.$msgbox
            .confirm("创建成功,是否退出创建文章页面", "提示", {
              confirmButtonText: "确定",
              cancelButtonText: "取消",
              type: "success",
            })
            .then(() => {
              this.$router.push("/article/index");
            });
        }
      } catch (err) {
        this.$message.error(err);
      }
    },
  },
};
</script>

<style scoped lang="scss">
.wrap {
  box-sizing: border-box;
  margin: 24px;
}
</style>
<style>
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  line-height: 178px;
  text-align: center;
}
.avatar {
  width: 178px;
  height: 178px;
  display: block;
}
</style>

4. 七牛云配置域名

  1. 点击七牛cdn 域名管理
  2. 添加域名,并在域名管理解析
  3. 配置域名的 CNAME

域名解析一般要半个小时,解析完要等一下才生效

上传图片并访问

http://cdn.at-will.cn/Fp30TD1fiuyL00qyuGuiqQwo0hNI

完整代码

相关推荐
活宝小娜1 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点1 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow1 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
刚刚好ā2 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
会发光的猪。5 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客5 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
前端李易安5 小时前
Webpack 热更新(HMR)详解:原理与实现
前端·webpack·node.js
周全全5 小时前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
ZwaterZ6 小时前
vue el-table表格点击某行触发事件&&操作栏点击和row-click冲突问题
前端·vue.js·elementui·c#·vue
码农六六6 小时前
vue3封装Element Plus table表格组件
javascript·vue.js·elementui