零基础手把手教你如何使用Laf免费玩转Midjourney后续之前端整合

这篇具有很好参考价值的文章主要介绍了零基础手把手教你如何使用Laf免费玩转Midjourney后续之前端整合。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

上篇讲述了 零基础手把手教你如何使用Laf免费玩转Midjourney,下面将讲解如何结合前端完成终极体验!

二、项目搭建

前端技术栈:vue + element plus

1.创建vue项目

这里使用vue脚手架创建项目,搭建项目步骤可参考官网 创建一个项目 | Vue CLIhttps://cli.vuejs.org/zh/guide/creating-a-project.html

2.安装element plus依赖并引入

安装步骤可参考官网 安装 | Element Plushttps://element-plus.gitee.io/zh-CN/guide/installation.html安装完成后在main.js中引入组件

import ElementPlus from 'element-plus'
import * as ElIcons from '@element-plus/icons-vue'
import 'element-plus/dist/index.css'
import locale from 'element-plus/lib/locale/lang/zh-cn'

const app = createApp(App)

for (const name in ElIcons) {
    app.component(name, ElIcons[name]);
}
app.use(ElementPlus, { locale })
app.use(store)
app.use(router)
app.mount('#app')

3.代码实现

修改“vue.config.js”文件中的配置,其中“target”为Laf接口访问前缀

module.exports = {
  transpileDependencies: true,
  lintOnSave: false,
  productionSourceMap: false,
  devServer: {
      proxy: {
          '/api': {
              target: 'https://xxx.laf.dev',
              changeOrigin: true,
              ws: false,
              pathRewrite: {
                  '^/api': ''
              }
          }
      }
  }
}

接着,完成页面布局和逻辑业务实现,以“home.vue”为例:

<template>
  <div class="page">
    <el-container>
      <el-header ref="elHeader">
        <p>欢迎体验Midjourney绘画功能~</p>
        <p>绘画指令:[/mj 提示词],例如:/mj a dog</p>
        <p>放大指令:[/mj u1-u4],例如:/mj u2</p>
        <p>变换指令:[/mj v1-v4],例如:/mj v3</p>
        <p class="tips">注意:提示词最好用英文!</p>
      </el-header>
      <el-main :style="{ height: scrollerHeight + 'px' }">
        <el-scrollbar class="msg-list">
          <el-row v-for="(item, key) in msgList" :key="key" class="msg-item">
            <el-col>
              <img v-if="item.type == 1" class="img_1" src="../assets/images/ic_chatgpt.png" />
              <el-card :style="{ 'margin-left': (item.type == 2 ? 'auto' : '0') }">
                <div class="txt">
                  <!-- <img class="img" v-if="item.content.indexOf('http') > -1" :src="item.content" /> -->
                  <el-image v-if="item.content.indexOf('http') > -1" :src="item.content"
                    :preview-src-list="[item.content]" fit="cover" />
                  <text v-else>{{ item.content }}</text>
                </div>
                <div class="time">{{ item.time }}</div>
              </el-card>
              <img v-if="item.type == 2" class="img_2" src="../assets/images/me.png" />
            </el-col>
          </el-row>
        </el-scrollbar>
      </el-main>
      <el-footer ref="elFooter">
        <el-input v-model="queryInfo.param.prompt" placeholder="/mj 提示词" clearable size="large"
          :formatter="(value) => `/mj ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
          :parser="(value) => value.replace(/\/mj\s?|(,*)/g, '')" :disabled="isDisabled">
          <template #append>
            <el-button type="primary" :disabled="isDisabled" @click="sendMsg()">
              <el-icon>
                <Position />
              </el-icon>发送
            </el-button>
          </template>
        </el-input>
      </el-footer>
    </el-container>
  </div>
</template>

<script>
import topBar from '@/components/topBar.vue'

var _this;
export default {
  name: 'home',
  components: {
    topBar
  },
  data() {
    return {
      // 容器高度初始化为0
      scrollerHeight: 0,
      // 查询参数信息
      queryInfo: {
        type: null,
        param: {
          msg_Id: null,
          prompt: '',
          question: null,
          index: null,
          id: null,
          url: null
        }
      },
      // 信息集合
      msgList: [],
      msgIndex: 0,
      isDisabled: false,
      // 图片信息
      imgInfo: null,
      // 操作类型 1-绘图,2-放大,3-变换
      operateType: 0,
      // 是否重试
      isRetry: true
    }
  },
  created() {
    _this = this;

    // 先读取缓存中的会话信息,没有则新创建一条
    const _msgList = localStorage.getItem('msgList');
    if (_msgList) {
      _this.msgList = JSON.parse(_msgList);
    } else {
      _this.insertMsg(1, '亲,欢迎加入Midjourney的绘画体验,请输入指令.....');
    }

    const _imgInfo = localStorage.getItem('imgInfo');
    if (_imgInfo) {
      _this.imgInfo = JSON.parse(_imgInfo);
    }
  },
  mounted: function () {
    _this.calculateHeight();

    // 当浏览器窗口大小发生变化时,重新计算容器高度
    window.addEventListener('resize', () => {
      _this.calculateHeight();
    });
  },
  methods: {
    // 计算容器高度
    calculateHeight() {
      // 获取顶部元素
      let elHeader = _this.$refs.elHeader;
      // 获取底部元素
      let elFooter = _this.$refs.elFooter;
      if (elHeader && elFooter) {
        _this.scrollerHeight = document.documentElement.clientHeight - elHeader.$el.offsetHeight - elFooter.$el.offsetHeight - 1;
      }
    },
    //发送消息
    sendMsg() {
      const _prompt = _this.queryInfo.param.prompt.replace(/\/mj\s?|(,*)/g, '').toLowerCase();
      if (!_prompt) {
        _this.$message.toast({
          message: '请输入提示词!'
        });
        return;
      }

      if (!_this.imgInfo && (_prompt.indexOf('u1') > -1 || _prompt.indexOf('u2') > -1 || _prompt.indexOf('u3') > -1 || _prompt.indexOf('u4') > -1
        || _prompt.indexOf('v1') > -1 || _prompt.indexOf('v2') > -1 || _prompt.indexOf('v3') > -1 || _prompt.indexOf('v4') > -1)) {
        _this.$message.toast({
          message: '请先输入绘图指令!'
        });
        return;
      }

      let optStr = '';
      _this.queryInfo.param.question = _prompt;
      // 放大图片
      if (_prompt.indexOf('u1') > -1 || _prompt.indexOf('u2') > -1 || _prompt.indexOf('u3') > -1 || _prompt.indexOf('u4') > -1) {
        optStr = '放大';
        _this.operateType = 2;
        _this.queryInfo.type = 'upscale';
        if (_prompt.indexOf('u1') > -1) {
          _this.queryInfo.param.index = 1;
        }
        if (_prompt.indexOf('u2') > -1) {
          _this.queryInfo.param.index = 2;
        }
        if (_prompt.indexOf('u3') > -1) {
          _this.queryInfo.param.index = 3;
        }
        if (_prompt.indexOf('u4') > -1) {
          _this.queryInfo.param.index = 4;
        }
        _this.queryInfo.param.id = _this.imgInfo.id;
        _this.queryInfo.param.url = _this.imgInfo.attachments[0].url;
      }
      //变化图片
      else if (_prompt.indexOf('v1') > -1 || _prompt.indexOf('v2') > -1 || _prompt.indexOf('v3') > -1 || _prompt.indexOf('v4') > -1) {
        optStr = '变化';
        _this.operateType = 3;
        _this.queryInfo.type = 'variation';
        if (_prompt.indexOf('v1') > -1) {
          _this.queryInfo.param.index = 1;
        }
        if (_prompt.indexOf('v2') > -1) {
          _this.queryInfo.param.index = 2;
        }
        if (_prompt.indexOf('v3') > -1) {
          _this.queryInfo.param.index = 3;
        }
        if (_prompt.indexOf('v4') > -1) {
          _this.queryInfo.param.index = 4;
        }
        _this.queryInfo.param.id = _this.imgInfo.id;
        _this.queryInfo.param.url = _this.imgInfo.attachments[0].url;
      }
      //生成图片
      else {
        optStr = '生成';
        _this.operateType = 1;
        _this.queryInfo.type = 'imagine';
        _this.queryInfo.param.msg_Id = 'amj_' + Math.ceil(Math.random() * 1000000000000);
      }

      _this.queryInfo.param.prompt = '';
      _this.insertMsg(2, _prompt);
      _this.isDisabled = true;
      _this.isRetry = true;
      console.log('请求参数', JSON.stringify(_this.queryInfo));
      _this.$requests
        .post("/api/mj-func", _this.queryInfo)
        .then((res) => {
          console.log('请求结果', res);
          if (res != null) {
            _this.$message.toast({
              message: res.msg,
              type: "success",
            });

            // 请求成功后,开始倒计时60秒
            let seconds = 60;
            _this.insertMsg(1, '请求成功,' + seconds + ' 秒后将为您获取' + optStr + '后的图片。');
            let timer = setInterval(function () {
              seconds--;
              if (seconds == 0) {
                console.log('执行查询');
                clearInterval(timer);
                _this.msgList[_this.msgList.length - 1].content = '图片获取中,请稍后......';
                localStorage.setItem('msgList', JSON.stringify(_this.msgList));

                _this.retrieveMessages();
                return;
              }
              _this.msgList[_this.msgList.length - 1].content = '请求成功,' + seconds + ' 秒后将为您获取' + optStr + '后的图片。';
              localStorage.setItem('msgList', JSON.stringify(_this.msgList));
            }, 1000);
          }
        });
    },
    // 查询消息
    retrieveMessages() {
      _this.queryInfo.type = 'retrieveMessages';
      console.log('查询参数', JSON.stringify(_this.queryInfo));
      _this.$requests
        .post("/api/mj-func", _this.queryInfo)
        .then((res) => {
          console.log('查询结果', res);
          _this.isDisabled = _this.isRetry ? true : false;
          if (res != null) {
            _this.isDisabled = false;
            _this.$message.toast({
              message: res.msg,
              type: "success",
            });

            if (res.data) {
              _this.insertMsg(1, res.data.pic);

              // 生成图片后,存储变量
              if (_this.operateType == 1) {
                _this.imgInfo = res.data;
                localStorage.setItem('imgInfo', JSON.stringify(_this.imgInfo));
              }
            }
          }
          else {
            if (_this.isRetry) {
              _this.isRetry = false;
              // 重试,开始倒计时180秒
              let seconds = 180;
              let timer = setInterval(function () {
                seconds--;
                if (seconds == 0) {
                  console.log('重试->执行查询');
                  clearInterval(timer);
                  _this.msgList[_this.msgList.length - 1].content = '图片获取中,请稍后......';
                  localStorage.setItem('msgList', JSON.stringify(_this.msgList));

                  _this.retrieveMessages();
                  return;
                }
                _this.msgList[_this.msgList.length - 1].content = '图片获取失败,' + seconds + ' 秒后将为您重新获取。';
                localStorage.setItem('msgList', JSON.stringify(_this.msgList));
              }, 1000);
            }
            else {
              _this.insertMsg(1, '十分抱歉,图片获取失败,请重新输入指令.....');
            }
          }
        });
    },
    // 插入会话
    insertMsg(type, content) {
      _this.msgIndex = _this.msgIndex + 1;
      _this.msgList.push({
        id: _this.msgIndex,
        type: type || 0,//类型 1-机器人,2-自己
        content: content || '',
        time: _this.$date.fmtDateTime(null, 3)
      });
      // 将会话写入缓存
      localStorage.setItem('msgList', JSON.stringify(_this.msgList));
    }
  }
}
</script>

<style lang="scss">
.page {
  .el-header {
    line-height: 20px;
    text-align: left;
    background-color: var(--el-color-primary-light-7);
    color: var(--el-text-color-primary);
    height: auto;
    padding: 8px 15px;

    p {
      font-size: 13px;
      color: #303133;
    }

    .tips {
      color: red;
    }
  }

  .el-main {
    padding: 12px 15px;

    .msg-list {
      .msg-item:last-child {
        margin-bottom: 0;
      }

      .msg-item {
        margin-bottom: 10px;
        text-align: left;

        .el-col {
          display: flex;

        }

        .img {
          width: 100%;
        }

        .img_1 {
          width: 36px;
          height: 36px;
          margin-right: 8px;
        }

        .img_2 {
          width: 36px;
          height: 36px;
          margin-left: 8px;
        }

        .el-card__body {
          padding: 8px 15px;
          font-size: 14px;
          color: #303133;
          min-width: 130px;
        }

        .time {
          margin-top: 5px;
          text-align: right;
          color: #909399;
          font-size: 12px;
        }
      }
    }
  }

  .el-footer {
    line-height: 60px;
    background-color: #ecf5ff;
    color: var(--el-text-color-primary);

    .el-input-group__append {
      background-color: #409EFF;
      color: #ffffff;
      box-shadow: none;
    }
  }
}
</style>

说明:post请求时,第一个url参数需要使用自己在Laf中创建的云函数的名称

在src目录下创建utils文件夹,用于存放以上关联的js,具体代码如下:

日期格式化(date.js)

//时间处理
const date = {
    /**
     * 
     * @param {时间} dateTime 
     * @param {类型} type 默认:年月日
     * type=1 年-月-日
     * type=2 年.月.日
     * type=3 年-月-日 时:分:秒
     * type=4 年.月.日 时:分:秒
     * @returns 
     */
    fmtDateTime(dateTime, type) {
        if (dateTime == '' || dateTime == null) {
            dateTime = new Date();
        } else {
            // dateTime = dateTime.substr(0, 4) + "/" + dateTime.substr(5, 2) + "/" + dateTime.substr(8, 2) + " " + dateTime.substr(11, 8);
            dateTime = new Date(dateTime);
        }

        var y = dateTime.getFullYear();
        var m = dateTime.getMonth() + 1;
        var d = dateTime.getDate();
        var h = dateTime.getHours() > 9 ? dateTime.getHours().toString() : '0' + dateTime.getHours();
        var mm = dateTime.getMinutes() > 9 ? dateTime.getMinutes().toString() : '0' + dateTime.getMinutes();
        var ss = dateTime.getSeconds() > 9 ? dateTime.getSeconds().toString() : '0' + dateTime.getSeconds();

        if (type === 1) {
            return y + '-' + (m < 10 ? ('0' + m) : m) + '-' + (d < 10 ? ('0' + d) : d);
        }
        else if (type === 2) {
            return y + '.' + (m < 10 ? ('0' + m) : m) + '.' + (d < 10 ? ('0' + d) : d);
        }
        else if (type === 3) {
            return y + '-' + (m < 10 ? ('0' + m) : m) + '-' + (d < 10 ? ('0' + d) : d) + " " + h + ":" + mm + ":" + ss;
        }
        else if (type === 4) {
            return y + '.' + (m < 10 ? ('0' + m) : m) + '.' + (d < 10 ? ('0' + d) : d) + " " + h + ":" + mm + ":" + ss;
        }
        return y + '年' + (m < 10 ? ('0' + m) : m) + '月' + (d < 10 ? ('0' + d) : d) + '日';
    }
}

export default date

消息弹框提示(message.js)

import { ElMessage } from "element-plus";

const message = {
    //信息提示
    toast(obj) {
        return ElMessage({
            message: obj.message || 'this is a message.',
            type: obj.type || 'warning',//success warning info error
            duration: obj.duration || 3000,
            showClose: obj.showClose || false
        });
    }
}

export default message

加载动画(loading.js)

import { ElLoading } from 'element-plus';

// 定义一个请求次数的变量,用来记录当前页面总共请求的次数
let loadingRequestCount = 0;
// 初始化loading
let loadingInstance;

// 编写一个显示loading的函数 并且记录请求次数 ++
const showLoading = (target) => {
    if (loadingRequestCount === 0) {
        // element的服务方式 target 我这边取的是表格class
        // 类似整个表格loading和在表格配置v-loading一样的效果,这么做是全局实现了,不用每个页面单独去v-loading
        loadingInstance = ElLoading.service({ target });
    }
    loadingRequestCount++
}

// 编写一个隐藏loading的函数,并且记录请求次数 --
const hideLoading = () => {
    if (loadingRequestCount <= 0) return
    loadingRequestCount--
    if (loadingRequestCount === 0) {
        loadingInstance.close();
    }
}

export {
    showLoading,
    hideLoading
}

http请求(requests.js)

import axios from 'axios'
import message from './message';
import { showLoading, hideLoading } from '@/utils/loading'

// 创建 axios 实例
const requests = axios.create({
    // baseURL: 'http://localhost:8088',
    withCredentials: true,
    headers: {
        // 'Content-Type': 'application/json',
        // 'content-type' : 'application/x-www-form-urlencoded',
        // 'auth': 'test'
    },
    timeout: 30 * 1000 // 请求超时时间 30秒
})

// 错误处理函数
const err = (error) => {
    // 响应拦截进来隐藏loading效果,此处采用延时处理是合并loading请求效果,避免多次请求loading关闭又开启
    setTimeout(() => {
        hideLoading()
    }, 200);

    if (error.response) {
        const data = error.response.data;
        if (error.response.status === 403) {
            message.toast({
                message: data.message || data.msg
            });
        }
        if (error.response.status === 401) {
            message.toast({
                type: 'warning',
                message: '你没有权限。'
            });
        }
    }
    return Promise.reject(error)
}

// requests interceptor(请求拦截器)
requests.interceptors.request.use(config => {
    // 请求拦截进来调用显示loading效果
    showLoading(".el-main");

    const token = localStorage.getItem('token')
    if (token) {
        config.headers['auth'] = token // 让每个请求携带自定义 token
    }
    return config
}, err)

// requests interceptor(接收拦截器)
requests.interceptors.response.use((response) => {
    // 响应拦截进来隐藏loading效果,此处采用延时处理是合并loading请求效果,避免多次请求loading关闭又开启
    setTimeout(() => {
        hideLoading()
    }, 200);

    const res = response.data;
    if (res.code == 200) {
        return Promise.resolve(res).catch((e) => { });
    } else {
        message.toast({
            message: res.msg
        });

        return Promise.reject(res).catch((e) => { });
    }
}, err)

export default {
    requests
}

同时,需要修改“main.js”,进行引入,配置全局变量

import message from './utils/message'
import requests from './utils/requests'
import date from './utils/date'

//配置全局属性
app.config.globalProperties.$requests = requests.requests
app.config.globalProperties.$message = message
app.config.globalProperties.$date = date

“App.vue”页面中样式如下:

<template>
  <router-view />
</template>

<style lang="scss">
body {
  padding: 0;
  margin: 0;
}

#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

p {
  margin: 0;
  padding: 0;
}

.el-message{
  width: max-content;
}
</style>

以为全部完成后,使用命令npm run serve运行项目,界面效果如下:

零基础手把手教你如何使用Laf免费玩转Midjourney后续之前端整合零基础手把手教你如何使用Laf免费玩转Midjourney后续之前端整合

 在线体验可点击 Midjourney绘画

三、发布项目并部署到Laf云平台

1.打包项目

本地开发完成后,没有服务器部署到线上怎么办?不用担心,Laf都已经为我们考虑好了,使用命令npm run build打包项目

2.项目托管

进入【Laf云开发】-【存储】,新建“Bucket”空间,如下图:

零基础手把手教你如何使用Laf免费玩转Midjourney后续之前端整合

 完成后,点击上方“上传”按钮,将本地打包后生成的dist文件夹下的文件全部上传,如下图:

零基础手把手教你如何使用Laf免费玩转Midjourney后续之前端整合

再点击右上方“开启网站托管”按钮,生成“当前域名”,即可进行外部访问了。

零基础手把手教你如何使用Laf免费玩转Midjourney后续之前端整合

 关于网站托管详细介绍,可访问官网 静态网站托管介绍 | laf 云开发https://doc.laf.run/guide/website-hosting/

以上即为使用Laf接入Midjourney后整合前端的完整演示,如有疑问,欢迎提出!文章来源地址https://www.toymoban.com/news/detail-492156.html

到了这里,关于零基础手把手教你如何使用Laf免费玩转Midjourney后续之前端整合的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 手把手教你如何免费Midjourney Adobe FireFly AI绘图—Window本地快速部署stable diffusion AI绘图及使用指南(小白也能学会)

    最近看到朋友圈最近各种文字生图、图生图,眼花缭乱的图片AI生成,我也心动了,于是赶紧研究了下目前业内认为最强大的 Midjourney、Adobe FireFly ,本来想试用下,奈何全球人民太热情了, Midjourney 被薅羊毛薅的不行了,原本 Midjourney 刚注册可以免费玩25次,现在也被Midjour

    2024年02月04日
    浏览(65)
  • 手把手教你如何使用SimiliarWeb

    在之前的“手把手教你如何使用Google Trends”文章中我们讲到从事跨境电商的卖家第一步遇到的问题是“客户在哪里?”该如何推广我的产品?因此若想自己的店铺做大做好,则需要工具来帮助分析市场行情,根据市场行情调整自己的业务状况。小编在上篇中已经讲解了三个特

    2024年02月09日
    浏览(66)
  • 手把手教你如何使用Docker

    我们在公司开发中,会有开发环境,测试环境,上线环境, 比如我们开发人员开发好了一个项目,在开发环境中运行正常,但测试人员拉到测试环境就跑不起来【jdk版本等】,或者上线的时候运行不起来,这时候就要为每个机器配置一个环境,那运维人员不得累死?【哈哈,

    2024年02月10日
    浏览(72)
  • 【Java技术专题】「Guava开发指南」手把手教你如何进行使用Guava工具箱进行开发系统实战指南(基础编程篇)

    Preconditions(前置条件):让方法调用的前置条件判断更简单 。 Guava在Preconditions 类中提供了若干前置条件判断的实用方法,我们强烈建议在 Eclipse 中静态导入这些方法。每个方法都有三个变种: 当方法没有额外参数时,抛出的异常中不包含错误消息,这会使得调用方很难确

    2024年02月07日
    浏览(78)
  • 手把手教你如何使用Fiddler抓包工具

    什么是 Fiddler? Fiddler 是一个 HTTP 协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的 HTTP 通讯。Fiddler 提供了电脑端、移动端的抓包、包括 http 协议和 https 协议都可以捕获到报文并进行分析;可以设置断点调试、截取报文进行请求替换和数据篡改,也可以进行

    2024年02月07日
    浏览(65)
  • 【零基础】手把手教你使用Docker部署Springboot项目(详细版)

    ​  本篇文章适合刚学完Docker,想要部署Springboot项目的小白;当然,如果你还没有学习Docker,只要严格按照本篇文章的步骤执行,理论上也是可以完成部署的。   我接下来部署的项目都是以一台全新Liunx服务器视角来操作,该服务器上jdk,mysql和Docker都还没有安装。 ​

    2024年01月20日
    浏览(59)
  • 手把手教你如何正确永久使用Microsoft Office365?

    office2019和office 365有什么区别的呢?为什么越来越多的人更加钟爱office365。简单来说office 2019的零售版本属于一次售出永久使用,价格上比较贵,而且功能上也不会再有更新。而office 365是一种基于云的订阅服务,我们花钱买的是一定时期的服务,在使用期间我们可以获得offi

    2024年02月07日
    浏览(62)
  • 手把手教你如何使用Unity搭建简易图片服务器

    目录 引言 服务器 WAMP简介 WAMP的配置与使用 主要的WAMP集成环境有: 正文 1、外部工具素材准备 首先下载并安装 WAMP  图片路径设置 2、创建 Unity 工程 将图片加载到 Unity 项目中: 代码块 运行效果如下: 网络游戏中,服务器的搭建尤为重要,无论是授权服务器,还是非授权服务

    2024年02月02日
    浏览(63)
  • 新人必看!手把手教你如何使用浏览器表格插件(下)

    本文由葡萄城技术团队于博客园原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 作为一名优秀的打工人,Excel是大家上班中必不可少的办公软件。随着互联网时代的到来,越来越多的公司开始使用各种B/S系统

    2024年02月06日
    浏览(65)
  • 新人必看!手把手教你如何使用浏览器表格插件(上)

    本文由葡萄城技术团队于博客园原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 作为一名优秀的打工人,Excel是大家上班中必不可少的办公软件。随着互联网时代的到来,越来越多的公司开始使用各种B/S系统

    2024年02月06日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包