菜单

金沙国际1. 术语表

2019年1月25日 - 金沙前端

多进程!!!

前方说道,JavaScript
天生单线程,固然再快,对于数据量较大时,也会产出拒绝响应的题材。因而必要Web Worker 或接近的方案去解决。

在那边自己不选拔 Web worker 的来头有如下几点:

  1. 有其他更好的代表方案:一个主进度能成立多个渲染进度,通过 IPC
    即可开展数据交互;
  2. Electron 不扶助 Web
    Worker!(当然,可能会在新本子匡助,最新新闻请关心官方)

Electron 小编在 2014.11.7 在《state of web worker support?》 issue
中平复了以下这一段:

Node integration doesn’t work in web workers, and there is no plan to
do. Workers in Chromium are implemented by starting a new thread, and
Node is not thread safe. Back in past we had tried to add node
integration to web workers in Atom, but it crashed too easily so we
gave up on it.

由此,大家最终利用了创办一个新的渲染进度 background process
举行处理多少。由 Electron 章节可见,每个 Electron
渲染进程是独立的,因而它们不会相互影响。但那也带动了一个题目:它们不可以相互通信?

错!上边有 3 种格局开展报纸发布:

  1. Storage
    API:对某个标签页的
    localStorage/sessionStorage 对象举办增删改时,其余标签页能因此window.storage 事件监听到。
  2. IndexedDB:IndexedDB
    是一个为了能够在客户端存储可观数额的结构化数据,并且在那个多少上使用索引举办高性能检索的
    API。
  3. 由此主进度作为中转站:设主界面的渲染进程是 A,background process
    是 B,那么 A 先将 Excel 数据传递到主进度,然后主进度再转车到 B。B
    处理完后再原路重回,具体如下图。当然,也足以将数据存储在主进程中,然后在多少个渲染进度中选取remote 模块来拜访它。

该工具选用了第三种艺术的首先种情景:
金沙国际 1

1、主页面渲染进度 A 的代码如下:

JavaScript

//① ipcRenderer.send(‘filter-start’, { filterTagList:
this.filterTagList, filterWay: this.filterWay, curActiveSheetName:
this.activeSheet.name }) // ⑥ 在某处接收 filter-response 事件
ipcRenderer.on(“filter-response”, (arg) => { // 获得处理数据 })

1
2
3
4
5
6
7
8
9
10
11
12
//①
ipcRenderer.send(‘filter-start’, {
    filterTagList: this.filterTagList,
    filterWay: this.filterWay,
    curActiveSheetName: this.activeSheet.name
})
 
// ⑥ 在某处接收 filter-response 事件
ipcRenderer.on("filter-response", (arg) => {
    // 得到处理数据
})
 

2、作为中转站的主进度的代码如下:

JavaScript

//② ipcMain.on(“filter-start”, (event, arg) => { // webContents
用于渲染和操纵 web page
backgroundWindow.webContents.send(“filter-start”, arg) }) // ⑤
用于收纳再次回到事件 ipcMain.on(“filter-response”, (event, arg) => {
mainWindow.webContents.send(“filter-response”, arg) })

1
2
3
4
5
6
7
8
9
10
11
//②
ipcMain.on("filter-start", (event, arg) => {
    // webContents 用于渲染和控制 web page
    backgroundWindow.webContents.send("filter-start", arg)
})
 
// ⑤ 用于接收返回事件
ipcMain.on("filter-response", (event, arg) => {
    mainWindow.webContents.send("filter-response", arg)
})
 

3、处理繁重数据的 background process 渲染进度 B 的代码如下:

JavaScript

// ③ ipcRenderer.on(‘filter-start’, (event, arg) => { // 举办演算 …
// ④ 运算达成后,再经过 IPC 原路再次回到。主进度和渲染进程 A
也要建立相应的监听事件 ipcRenderer.send(‘filter-response’, { filRow:
tempFilRow }) })

1
2
3
4
5
6
7
8
9
10
11
// ③
ipcRenderer.on(‘filter-start’, (event, arg) => {
    // 进行运算
    …
 
    // ④ 运算完毕后,再通过 IPC 原路返回。主进程和渲染进程 A 也要建立相应的监听事件
    ipcRenderer.send(‘filter-response’, {
        filRow: tempFilRow
    })
})
 

迄今,大家将『读取文件』、『过滤数据』和『导出文件』三大耗时的数码操作均转移到了
background process 中处理。

此处,大家只开创了一个
background process,若是想要做得更然则,我们得以新建『CPU 线程数- 1 』
个的 background process
同时对数码举行拍卖,然后在主进程对拍卖后数据开展拼接,最终再将拼接后的数目重临到主页面的渲染进度。那样就可以尽量榨干
CPU 了。当然,在此小编不会开展这些优化。

毫不为了优化而优化,否则贪小失大。 —— 某网友

Linux

$ ./electron/electron your-app/

process

一个进度是一个正在运转的微机程序的实例。Electron应用实际上是接纳主进程和一个或多少个渲染进程同时运转多少个程序。

Node.js和Electron中,每一个运转着的进度都是一个process对象。那些目的是一个大局的并提供有关当前进度的新闻和决定。作为一个大局的,它在利用中不应用require()也是立见成效的。

参见:main
process, renderer
process

前者框架的强盛及干练

性能优化

上面谈谈『性能优化』,那有些关乎到运转功能内存占用量
注:以下内容均根据 Excel 样例文件(数据量为:1913 行 x 180
列)得出的定论。

高速入门

Electron 可以让您使用纯 JavaScript 调用丰硕的原生 APIs
来创制桌面应用。你可以把它当作一个留意于桌面应用的 Node.js
的变体,而不是 Web 服务器。

那不意味着 Electron 是绑定了 GUI 库的 JavaScript。相反,Electron 使用
web 页面作为它的 GUI,所以你能把它作为成一个被 JavaScript
控制的,精简版的 Chromium 浏览器。

Squirrel

Squirrel是一个开源的框架,可以允许Electron应用自动升级到曾经公告的风靡版本。查看autoUpdater接口的施用Squirrel启动的音信。

Vue.js、React.js 及 Angular.js 等等前端开发框架引入了 UI =
framework(State)
的前端编程逻辑,大范围下落了前者业务开支的难度,尤其是面向复杂前端选择。而那个优质开源框架的普及、多端业务合并、前后端分离的急需让越来越多的架构设计将大多数事情逻辑写在了前者。

有关小编:刘健超-J.c

金沙国际 2

前端,在路上…
个人主页 ·
我的篇章 ·
19 ·
    

金沙国际 3

打造你首先个 Electron 应用

大致上,一个 Electron 应用的目录结构如下:

your-app/
├── package.json
├── main.js
└── index.html

package.json 的格式和 Node 的完全一致,并且卓殊被 main
字段申明的本子文件是您的拔取的开行脚本,它运行在主进程上。你采纳里的
package.json 看起来应当像:

{
  "name"    : "your-app",
  "version" : "0.1.0",
  "main"    : "main.js"
}

注意:如果 main 字段没有在 package.json 申明,Electron会优先加载
index.js

main.js 应该用于创设窗口和拍卖系统事件,一个顶尖的例证如下:

const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')

// 保持一个对于 window 对象的全局引用,如果你不这样做,
// 当 JavaScript 对象被垃圾回收, window 会被自动地关闭
let win

function createWindow () {
  // 创建浏览器窗口。
  win = new BrowserWindow({width: 800, height: 600})

  // 加载应用的 index.html。
  win.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // 打开开发者工具。
  win.webContents.openDevTools()

  // 当 window 被关闭,这个事件会被触发。
  win.on('closed', () => {
    // 取消引用 window 对象,如果你的应用支持多窗口的话,
    // 通常会把多个 window 对象存放在一个数组里面,
    // 与此同时,你应该删除相应的元素。
    win = null
  })
}

// Electron 会在初始化后并准备
// 创建浏览器窗口时,调用这个函数。
// 部分 API 在 ready 事件触发后才能使用。
app.on('ready', createWindow)

// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
  // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
  // 否则绝大部分应用及其菜单栏会保持激活。
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // 在这文件,你可以续写应用剩下主进程代码。
  // 也可以拆分成几个文件,然后用 require 导入。
  if (win === null) {
    createWindow()
  }
})

// 在这文件,你可以续写应用剩下主进程代码。
// 也可以拆分成几个文件,然后用 require 导入。

说到底,你想突显的 index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using node <script>document.write(process.versions.node)</script>,
    Chrome <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
  </body>
</html>

Brightray

Brightray是一个使libchromiumcontent更便于接纳应用的静态库。它是专程为了Electron而制造的,不过也得以允许尚未基于Electron的原生应用使用Chromium的渲染引擎。

布赖特ray是Electron的一个平底的依赖性,大部分Electron的使用者并不用担心它。

七牛云大数量平台建设进行

打赏支持自己写出更加多好小说,谢谢!

任选一种支付办法

金沙国际 4
金沙国际 5

1 赞 2 收藏
评论

Windows

$ .\node_modules\.bin\electron .

renderer process

在您的应用中,渲染进度就是一个浏览器窗口。差距于主进程,可以有五个渲染进度并且每一个渲染进度都看作一个相间的长河来运作。它们也足以被埋伏。

相似的浏览器中,网页平时运行在一个沙盒环境中,并且不容许调用本地资源。Electron的使用者有义务使用Node.js接口来与底层的操作系统哦交互。

参考:process,main
process

Render Function 

金沙国际 6

图 5 

 

有了 Virtual  DOM 这一层用 JavaScript 代表 DOM 之后,用 Render Function
把 DOM 再刷出去即可。由此,Render Function 也是 2.0 已毕的,1.0
只好定义页面和逻辑,它来帮你做任何,而 2.0 之后方可用 Render Function
,那是一段把 Virtual  DOM 变成 DOM 的逻辑(图 5 )。

 

最大的价值在于,因为有 Render Function ,把 JavaScript 变成实际 DOM
那些函数,同样把后端能明了的 Object 在后端提前用 Render Function 输出
HTML ,那样后端就已经把它输出来了,直接 Drive
给前端,那些页面就早已有了。也足以把一个 JavaScript 表明的 DOM
输出成真正的 HTML 给前端,后端渲染就完了了。

 

内存占有量过大

化解了举行功用和渲染问题后,发现也设有内存占用量过大的题目。当时臆想是以下多少个原因:

  1. 三大耗时操作均放置在 background process
    处理。在简报传递数据的经过中,由于不是共享内存(因为 IPC 是根据Socket
    的),导致出现多份数据副本(在写那篇小说时才有了那相对合适的答案)。
  2. Vuex
    是以一个大局单例的格局开展管制,但它会是否对数码做了几许封装,而造成性能的损耗呢?
  3. 出于 JavaScript
    近年来不享有积极回收资源的力量,所以只好积极对闲置对象设置为
    null,然后等待 GC 回收。

是因为 Chromium 采纳多进度架构,由此会涉及到进度间通讯问题。Browser
进度在起步 Render 进度的进度中会建立一个以 UNIX Socket 为根基的 IPC
通道。有了 IPC 通道之后,接下去 Browser 进度与 Render
进度就以信息的花样开展通讯。大家将那种新闻称为 IPC
信息,以分别于线程新闻循环中的信息。
——《Chromium的IPC音讯发送、接收和散发机制分析》

概念:为了便于领悟,以下『Excel 数据』均指 Excel 的一切一蹴而就单元格转为
JSON 格式后的多少。

最不难处理的真切是第三点,手动将不再须求的变量及时安装为
null,但效率并不鲜明。

新生,通过操作系统的『活动监视器』(Windows
上是天职管理器)对该工具的每阶段(打开时、导入文本时、筛选时和导出时)进行简要的内存分析,得到以下报告:

—————- S:报告分割线 —————-
经观望,首要耗内存的是页面渲染进度。上面通过截图评释:
PID 15243 是主进度
PID 15246 是页面渲染进程
PID 15248 是 background 渲染进度

a、首次启动程序时(第 4 行是主进度;第 1 行是页面渲染进程;第 3 行是
background 渲染进度 )

金沙国际 7

b、导入文本(第 5 行是主进度;第 2 行是页面渲染过程;第 4 行是
background 渲染进度 )
金沙国际 8

c、筛选数据(第 4 行是主进度;第 1 行是页面渲染进程;第 3 行是
background 渲染进程 )
金沙国际 9

鉴于 JavaScript 近年来不具有积极回收资源的成效,所以只可以积极将对象设置为
null,然后等待 GC 回收。

于是,经过一段时间等待后,内存占用如下:
d、一段时间后(第 4 行是主进程;第 1 行是页面渲染进程;第 3 行是
background 渲染进程 )
金沙国际 10

由上述可得,页面渲染进程由于页面元素和 Vue 等 UI
相关资源是固定的,占用内存较大且无法回收。主进度占用资源也不可以得到很好释放,暂时不了解原委,而
background 渲染进度则较好地释放资源。

—————- E:报告分割线 —————-

根据报告,早先得出的结论是 Vue 和电视发布时占用资源较大。

据悉该工具的莫过于行使场景:Excel
数据只在『导入』和『过滤后』多个级次需要出示,而且突显的是经过
JavaScript 拼接的 HTML 字符串所组成的 DOM 而已。因而将表格数据放置在
Vuex 中,有点滥用资源的疑虑。

另外,在 background process 中也有存有一份 Excel
数据副本。由此,索性只在 background process 存储一份 Excel
数据,然后每当数据变动时,通过 IPC 让 background process 再次来到拼接好的
HTML
字符串即可。那样一来,内存占有量立时下落许多。别的,那也是一个一举多得的优化:

  1. 字符串拼接操作也转移到了
    background process,页面渲染进度进一步削减耗时的操作;
  2. 内存占有量大大减小,响应速度也收获了提拔。

实际,那也有点像 Vuex 的『全局单例方式管理』,一份数据就好。

当然,对于 Excel 的主干音信,如行列数、SheetName、标题组等均依旧保留在
Vuex。

优化后的内存占有量如下图。与上述报告的第三张图相比较(同一等级),内存占有量下跌了
44.419%: 金沙国际 11
别的,对于不要求响应的多少,可由此 Object.freeze()
冻结起来。这也是一种优化手段。但该工具近来并从未利用到。

迄今,优化部分也讲演完结了!


该工具近日是开源的,欢迎大家利用或引进给用研组等有要求的人。

你们的反馈(可提交 issues /
pull
request)能让这些工具在选拔和效果上不断完善。

最后,感谢 LV
在成品计划、界面设计和优化上的暴力支撑。全文完!

打赏扶助我写出更多好小说,谢谢!

打赏作者

macOS

$ ./Electron.app/Contents/MacOS/Electron your-app/

Electron.app 里面是 Electron 发表包,你可以在
这里
下载到。

NSIS

Nullsoft Scriptable Install System是一个Microsoft
Windows下的台本驱动的设置制作工具。它揭橥在免费软件许可证下,是一个接近于InstallShield的广大的被用来顶替商业专有产品的工具。electron-builder扶助NSIS作为一个编译目的。

而是,纯前端产品也有所它的题材。上述的几个前端框架都协理了后端渲染的功力,从而融合了前后端的问题。怎么着有效地构成现有前端逻辑完毕后端渲染、怎样优化后端渲染性能、怎么着落实服务器流式吐内容更快地渲染页面的阅历,会成为新一代
Web 开发的趋势,提升前端业务支出的功用。在由七牛云主办的 ECUG
十周年盛会上,阴明为我们带来了他的履行分享。

它由哪些组成?

Electron 结合了 ChromiumNode.js 和用于调用操作系统本地成效的
API(如打开文件窗口、公告、图标等)。

金沙国际 12

Windows

$ .\electron\electron.exe your-app\

webview

webview标签是被用来在你的Electron应用中放置“guest”(例如一个外表网页)内容。他们是丰裕相像的内嵌框架,可是分化之处在于每一个webview运转在一个点名的进度中。它并不曾和您的网页拥有相同的权能,并且在您的运用和松手内容之间相互都是异步的。那将维持你的行使对于嵌入内容的安全性。

阴明(掘金联合创办人、首席营业官)

汇成一句话

Electron 应用就像是 Node 应用,它也依靠一个 package.json
文件。该公文定义了哪个文件作为主进度,并由此让 Electron
知道从何启动应用。然后主进度能创立渲染进度,并能使用 IPC
让双方间进行信息传递。

金沙国际 13

迄今,Electron
的根底部分介绍已毕。该有的是基于小编之前翻译的一篇小说《Essential
Electron》,译文可点击
这里。


主进程与渲染进度的不一致

主进度使用 BrowserWindow 实例创制页面。每个 BrowserWindow
实例都在融洽的渲染进度里运行页面。当一个 BrowserWindow
实例被销毁后,相应的渲染进度也会被为止。

主进度管理所有页面和与之对应的渲染进程。每个渲染进度都是相互独立的,并且只关心他们自己的页面。

是因为在页面里保管原生 GUI
资源是老大危急而且简单造成资源败露,所以在页面调用 GUI 相关的 APIs
是不被允许的。若是你想在网页里应用 GUI
操作,其对应的渲染进度必须与主进度举办电视发表,请求主进度展开相关的 GUI
操作。

在 Electron,我们提供三种办法用于主进度和渲染进程之间的通信。像
ipcRenderer
ipcMain
模块用于发送音讯, remote
模块用于 RPC 格局通讯。那几个内容都得以在一个 FAQ 中查看 how to share
data between web
pages。

IPC

IPC是Inter-Process
Communication的简称。Electron使用IPC在主进程和渲染进度以内发送系列化的JSON新闻。

Stream

要是在 Vue 业务包在一个 function call 中并接上 Window  contex,服务器
renderer 获得有关事情 js 文件吐出内容。Vue.js 2.0 协理 Stream
后但流式数据,在 HTML 完整生成从前的向前端吐数据。

 

js-xlsx

该库帮忙各个电子表格格式的辨析与变化。它由 JavaScript 完结,适用于前者和
Node。详情>>

时下支撑读入的格式有(不断更新):

支撑写出的格式有:

眼前该库提供的 sheet_to_json 方法能将读入的 Excel 数据转为 JSON
格式。而对此导出操作,大家必要为 js-xlsx 提供指定的 JSON 格式。

越多关于 Excel 在 JavaScript
中处理的知识可查阅凹凸实验室的《Node读写Excel文件探究实践》。但该小说存在两处问题(均在
js-xlsx 实战的导出表格部分):

  1. 浮动尾部时,Excel 的列音讯简单地因此 String.fromCharCode(65+j)
    生成。当列大于 26 时会现身问题。那些问题会在后头章节中提交解决方案;
  2. 转换成 worksheet
    须求的构造处,出现逻辑性错误,并且会促成严重的性能问题。逻辑问题在此不讲述,我们看看性能问题:
    随着 ECMAScript 的不断更新,JavaScript
    变得更其强硬和易用。固然如此,大家如故要形成『物尽所用』,而不要『大材小用』,否则恐怕会博得“反效果”。那里导致性能问题的难为
    Object.assign()
    方法,该措施能够把自由多个源对象的可枚举属性拷贝至目的对象,并回到目的对象。由于该办法本身的兑现机制,会在此案例中发出大批量的冗余操作。在此案例中,单元格音信是绝无仅有的,所以平昔通过
    forEach 为一个空对象赋值即可。升高 N
    倍性能的还要,也把逻辑性错误解决了。

原来的:

JavaScript

var result = 某数组.reduce((prev, next) => Object.assign({}, prev,
{[next.position]: {v: next.v}}), {});

1
2
var result = 某数组.reduce((prev, next) =&gt; Object.assign({}, prev, {[next.position]: {v: next.v}}), {});
 

改为:

JavaScript

var result = 某数组.forEach((v, i) => data[v.position]= {v: v.v})

1
2
var result = 某数组.forEach((v, i) =&gt; data[v.position]= {v: v.v})
 

实施是查验真理的唯一标准

在了解上述知识后,上面就谈谈在该项目实行中总计出来的技能、难点和严重性

参考上边例子

复制并且运行那个库
electron/electron-quick-start

注意:运作时索要您的体系现已设置了
Git 和
Node.js(包含
npm)。

# 克隆这仓库
$ git clone https://github.com/electron/electron-quick-start
# 进入仓库
$ cd electron-quick-start
# 安装依赖库并运行应用
$ npm install && npm start

越多 apps 例子,查看 electron 社区创造的 list of
boilerplates。

本条页面定义了有些在Electron中时常使用的专出名词。

开源帮衬

Vue
的生态繁荣,很大片段来自整个生态周边环境的支撑,比如脚手架、组件化、路由、状态管理、
Ajax 、前端开发工具、前端组件库、后端渲染。在 Vue
的前端方案上,中国早已比海外强,开发质料很高。后端渲染,迟早会有一个很牛的库出来帮我们,很心痛从前并未,可是最终有了,叫做
Nuxt.js 。

 

Nuxt.js 是一个像样于
Next.js(React)的开源后端渲染库,它支持的并不是后端渲染这一层的工作,它做了一套通解,想要用 Vue
的作业去支付,但与此同时帮忙 code-splitting 、generation
等不等的布局文件,它都会有一套不错的缓解方案生成。可是大家都是后端的大师,最后可能不甘于用外人的化解方案。然而像相比较偏前端的人来讲,它的基础解决方案已经解决很大题目了。

 

为 Electron 应用生成 Windows 安装包

通过 electron-builder 可间接生成常见的
MacOS 安装包,但它生成的 Windows 的安装包却略显简洁(默许选项时)。

金沙国际 14
Mac 常见的设置方式,将“左侧的施用图标”拖拽到“左侧的 Applications”即可

经过 electron-builder 生成的 Windows 安装包与大家在 Windows
上常见的软件安装界面不太一样,它并未设置向导和点击“下一步”的按钮,只有一个设置时的
gif 动画(默许的 gif 动画如下图,当然你也可以指定特定的 gif
动画),由此也就关闭了用户选拔设置路径等义务。

金沙国际 15
Windows 安装时 默许突显的 gif
动画

倘使您想为打包后的 Electron 应用(即透过
electron-packager/electron-builder
生成的,可径直运行的次第目录)生成拥有点击“下一步”按钮和可让用户指定安装路径的宽泛安装包,可以品味
NSIS 程序,具体可看这篇教程 《[教學]只要10分鐘學會使用 NSIS
包裝您的桌面軟體–安裝程式打包。完全免費。》。

注:electron-builder
也提供了扭转安装包的配备项,现实查看>>。

NSIS(Nullsoft Scriptable Install System)是一个开源的 Windows
系统下安装程序制作程序。它提供了安装、卸载、系统安装、文件解压缩等效能。正如其名字所描述的那样,NSIS
是透过它的脚本语言来描述安装程序的表现和逻辑的。NSIS
的脚本语言和常见的编程语言有相近的构造和语法,但它是为安装程序那类应用所安顿的。

迄今,CSS、JavaScript 和 Electron 相关的学识和技巧部分解说落成。


electron-prebuilt

electron
是一个 npm 模块,包蕴所使用的 Electron 预编译版本。
要是您早就用 npm 全局安装了它,你只须要按照如下方式直接运行你的采取:

electron .

比方您是局地安装,那运行:

原文:https://github.com/electron/electron/blob/master/docs/glossary.md
译者:Lin


Electron

macOS / Linux

$ ./node_modules/.bin/electron .

DMG

Apple Disk
Image是一个在MacOS上选用的打包类型。DMG文件一般用来散发应用的“安装文件”。electron-builder帮助dmg作为一个装进目的。

A Simple Vue.js Program

金沙国际 16

 

为 DOM 的 File 对象增添了 path 属性

Electron 为 File 对象额外增了 path
属性,该属性可获得文件在文件系统上的真正路径。因而,你可以运用 Node
横行霸道。应用场景有:拖拽文件后,通过 Node 提供的 File API
读取文件等。

手工下载 Electron 二进制文件

若果你手工下载了 Electron
的二进制文件,你也得以一向利用其中的二进制文件直接运行你的施用。

V8

V8是谷歌的开源JavaScrip引擎。它是用C++编写的还要被用在谷歌(Google)Chrome中,Chrome是谷歌(Google)的开源浏览器。V8能够独立运行,或者被安置到任何C++应用中。

谢孟军:The State of Go

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图