手把手教你写一个生成yapi接口代码Chrome 扩展插件

1,312 阅读5分钟

我正在参加「掘金·启航计划」

是的,我就是想要掘金包包,熬夜写下这篇文章。可能你觉得水,但你不能质疑我想要包包的精神!!

这篇文章适用于使用yapi平台管理接口的同学阅读,不过,如果贵司用别的接口管理平台的话也可来参考参考哦

代码地址(遇到不懂的地方可以直接对照源码)

github.com/Stacey1018/…

背景

原因我们Chrome扩展插件只能一个接口一个接口的生成代码,需要实现一个批量生成接口代码的功能,于是leader钉钉发给我一个链接就让我搞(还挺有良心,知道我没接触过Chrome插件)。

于是搜索了下相关Chrome开发知识,我们就能上手开发了

前期准备工作

有了扩展插件开发的基础知识,很容易就能上手了。

manifest.json

创建一个文件夹 custom-api

在根目录创建文件manifest.json,这个文件是扩展必须的文件,是用来描述扩展的功能和配置

manifest.json

{
    "manifest_version": 3, 
    "name": "Hello Extensions",
    "description": "Base Level Extension",
    "version": "1.0",
    "action": {
      "default_popup": "hello.html", //点击图表弹出的窗口
      "default_icon": "hello_extensions.png" // 扩展图标
    }
}

自己准备图标

根目录下创建hello.html (点击图表弹出的窗口)

<html>
  <body>
    <h1>Hello Extensions</h1>
  </body>
</html>

当前目录是这样的

├── hello.html
├── hello_extensions.png
└── manifest.json

接下来就可以放到浏览器扩展工具里面看效果了

image.png

构建项目

需要通过jq去操作dom,在项目中引入jquery

需要一个树插件引入,我选择了zTree

我们对扩展程序有了一个基础的认识,现在调整下目录结构,让它看起来更规范

调整后的目录

├── background.js
├── images
│   └── hello_extensions.png
├── js
│   ├── jquery-3.5.1.min.js
│   └── zTree
├── manifest.json
├── popup
│   ├── hello.html
│   ├── popup.css
│   └── popup.js

yapi开放的公共接口

先找下yapi 开放的公共接口,我们需要的就是

/api/interface/list_menu

是的,这一个接口就可以满足我们的需求

image.png

开始开发

先准备好我们的popup.html 内容如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
	  <meta name="viewport" content="width=device-width, initial-scale=1.0">
	  <link rel="stylesheet" href="../js/zTree/css/zTreeStyle/zTreeStyle.css" media="all">
	  <link rel="stylesheet" href="popup.css" media="all">
  </head>
  <body>
    <div class="pop-up-wrap">
      <p class="pop-up-title">点击按钮复制api</p>
      <div class="ztreeContent">
        <div class="pop-up-ztree-loading" >
          <p>正在获取页面数据中...</p>
          <p>若长时间没获取到数据,请刷新页面重试</p>
        </div>
        <ul id="treeDemo" class="ztree"></ul>
      </div>
      <div class="copy-btn-wrap">
        <button id="generate" class="copy-btn" >生成代码</button>
      </div>
      <div class="pop-up">
        <div class="pop-up-content-wrap" >
          <div class="pop-up-loading" >
            <p>正在获取页面数据中...</p>
            <p>若长时间没获取到数据,请刷新页面重试</p>
          </div>
          <div id="copty_content" class="pop-up-content"></div>
          <div class="pop-up-fail">获取页面数据失败,请在所需页面手动输入api</div>
        </div>
        <div class="copy-btn-wrap">
          <button id="cpoty_btn" class="copy-btn" data-clipboard-action="copy" data-clipboard-target="#copty_content">复制</button>
        </div>
      </div>
      <div class="copy-success-wrap">
        <p class="copy-success-text">复制成功</p>
      </div>
    </div>
  <script type="text/javascript" src="../js/jquery-3.5.1.min.js"></script>
	<script type="text/javascript" src="../js/zTree/js/jquery.ztree.all.min.js"></script>
  <script src="popup.js"></script>
</body>
</html>

css

* {
    margin: 0;
    padding: 0;
  }
  html, body {
    width: 100%;
    height: 100%;
  }
  
  button {
    margin: 0px;
    padding: 0px;
    border: 0px;
    outline: none;
  }
  
  .pop-up-wrap {
    width: 400px;
    background: #eee;
  }
  
  .pop-up-title {
    font-size: 16px;
    line-height: 40px;
    text-align: center;
    background: #fff;
    border-bottom: #ccc 1px solid;
  }
  
  .pop-up {
    padding: 10px 20px 20px;
    display: none;
  }
  
  .pop-up-content-wrap {
    padding: 10px;
    background: #fff;
    border: solid 1px #ccc;
    border-radius: 10px;
  }
  
  .pop-up-content {
    display: none;
    max-height: 500px;
    overflow: auto;
  }
  
  .pop-up-content span {
    display: block;
    word-wrap: break-word;
  }

  
  .pop-up-fail {
    display: none;
  }
  
  .copy-btn-wrap {
    margin-top: 10px;
    text-align: right;
  }
  
  .copy-btn {
    display: inline-block;
    width: 60px;
    height: 30px;
    color: #fff;
    background: rgba(0, 216, 201, .8);
    border-radius: 6px;
  }
  
  .copy-success-wrap {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 20px;
    width: 200px;
    text-align: center;
    background: rgba(235, 235, 235, .8);
    border-radius: 10px;
    display: none;
  }
  
  .copy-success-text{
    font-size: 20px;
    line-height: 40px;
  }
  .ztreeContent{
    background-color: #fff;
    height: 200px;
    overflow: auto;
  }
  
  .code{
    display: none;
    margin-top: 10px;
  }
  
  .pop-up-content-code{
    height: 300px;
    overflow: auto;
  }

现在页面如下 image.png

如何调试

在弹框页面,右击检查,会看到一个控制台,这就是扩展程序的控制台,可以在console里查看打印信息 image.png

content script

谷歌插件支持 content script(内容脚本),它是独立运行在一个环境中的,不会与其他扩展可以主页发生冲突。这里我们需要用它来进行一个通信

根目录创建文件夹 scripts 文件夹下创建 content.js

mainfest.json 添加 content_scripts 字段

注意:这里的http://yapi.smart-xwork.cn/* 在使用时必须是你自己的yapi平台地址,不要写成这个哦

 "content_scripts": [
      {
        "js": ["scripts/content.js"],
        "matches": [
         "http://yapi.smart-xwork.cn/*" //这个是必须的,只有这个网站地址下才可用
        ]
      }
    ]

popup.js里面我们发出一条信息和内容脚本进行通信

// 发送消息给content-script
function sendMeaasgeToContentScript (message, callback) {
    chrome.tabs.query({
      active: true,
      currentWindow: true
    }, function (tabs) {
      chrome.tabs.sendMessage(
        tabs[0].id,
        message,
        function (response) {
          if (callback) callback(response)
        }
      )
    })
}

document.addEventListener('DOMContentLoaded', function() {
  console.log(chrome.extension.getURL)
  console.log(window)
    sendMeaasgeToContentScript({
    from: 'popup',
    subject: 'DOMInfo'
  }, function (response) {
    if (response?.href) {
      console.log(response.href)
    }
  })
});

content.js监听信息

// 监听来自popup的消息
chrome.runtime.onMessage.addListener(function (msg, sender, response) {
  if ((msg.from === 'popup') && (msg.subject === 'DOMInfo')) {
		response({location: window.location})
  }
});

popup 会接收到返回的{{location: window.location}} 我们可以看到控制台输出了location

image.png

由此,我们可以在popup.js中得到当前访问的页面路径,即yapi的地址,

请求数据

我们请求yapi接口列表

代码如下

var zTreeObj
var url
document.addEventListener('DOMContentLoaded', function() {
    sendMeaasgeToContentScript({
    from: 'popup',
    subject: 'DOMInfo'
  }, function (response) {
    if (response?.location) {
        console.log(response.location)
        getTreeData(response.location) // 这里调接口
    }
  })
});



// 获取yapi接口列表
function getTreeData (location) {
  url =  location.origin

  const id = location.href.split('/')[4]
  const origin = location.origin // http://yapi.smart-xwork.cn
	$.ajax({
		type:'GET',
		url:`${origin}/api/interface/list_menu?project_id=${id}`,
		dataType:'json',
		success:function(response){
			const {
				errcode,
				data
			} = response
			if (errcode === 0) {
        data.forEach(element => {
          element.title = element.name
        });
        console.log(data)
			}
		},
		error: function(response){
      const str = JSON.stringify(response)
		}
	});
}


// 初始化zTree zTree的使用方法可以去官网查看
function initZTree(data){
  // zTree 的参数配置,深入使用请参考 API 文档(setting 配置详解)
  var setting = {
    check:{
      enable:true,
    },
    data:{
      key:{
        children:'list',
        name:'title'
      }
    }

  };
  $(document).ready(function(){
     zTreeObj = $.fn.zTree.init($("#treeDemo"), setting, data);
  });
}


image.png

我们已经获取到数据了,通过调用initZtree方法,可以将接口列表展示到窗口中

image.png

生成代码

选中接口,我们开始根据选中的数据生成我们想要的代码

效果图

image.png

看看代码实现

// 下划线转驼峰
function toHump(name) {
	return name.replace(/\_(\w)/g, function(all, letter){
			return letter.toUpperCase();
	});
}

$('#generate').click(()=>{
  $('.pop-up').show()
  const checkedArr = zTreeObj.getNodesByFilter((node)=>{
    return node.level==1 && node.checked
  })

  // 遍历生成代码
  let code = ``

  checkedArr.forEach(item=>{
    let _path = item.path.split('/').slice(-2).join('_')
    _path = _path.replace(_path[0], _path[0].toUpperCase())
    const _method = item.method.toLowerCase()
    const _urlName = `${_method}${toHump(_path)}`
    code += `
      <span>/** </span>
      <span>&nbsp;* ${item.title}</span>
      <span>&nbsp;* @desc: ${url}/project/${item.project_id}/interface/api/${item._id}</span>
      <span>&nbsp;* @mock: ${url}/mock/${item.project_id}${item.path}</span>
      <span>&nbsp;*/</span>
      <span class="pop-up-url">${_urlName} = ${_method}('${item.path.replace(/^(\s|\/)+|(\s|\/)+$/g, '')}')</span>
    `
  })

  console.log(code)

  $('.pop-up-loading').hide()
  $('.pop-up-content').show()
  $('.pop-up-content').html(
    code
  )
})

复制代码

这里复制用到一个插件,就不做过多介绍了

用法 html

 <div class="copy-btn-wrap">
          <button id="cpoty_btn" 
          class="copy-btn" 
          data-clipboard-action="copy"  // 触发的方法
          data-clipboard-target="#copty_content" // 复制的元素id
          >复制</button>
        </div>

popup.js

$(function(){
  copy()
});

// 复制代码
function copy () {
  const clipboard = new ClipboardJS('#cpoty_btn'); 
  clipboard.on('success', function(e) {
    $('.copy-success-wrap').show()
    setTimeout(() => {
      $('.copy-success-wrap').hide()
    }, 1000);
  });
  clipboard.on('error', function(e) {
    alert("复制失败!请手动复制")
  });
}

至此 一个快速生成接口代码的插件就完成了(写的较粗,可自行更改样式)