LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

都2024年了,做WEB開發(fā)的還不知道 Web Components 呢!

admin
2024年3月27日 16:37 本文熱度 1235

網(wǎng)絡(luò)技術(shù)的快速發(fā)展,帶來了層出不窮的新概念和框架,尤其是在前端開發(fā)領(lǐng)域,新技術(shù)的出現(xiàn)如同浪潮般一波接一波,例如 Vue3 和 Vite 的組合。而在這種技術(shù)快速更新的環(huán)境中,Web Components 作為一項(xiàng)已經(jīng)存在一段時(shí)間的技術(shù),為什么仍然值得我們深入學(xué)習(xí)和探討呢?

---- 文章的篇幅可能較長(zhǎng),借助目錄效果更好。

Web Components 是由 W3C 推動(dòng)的標(biāo)準(zhǔn)化技術(shù),它得到了包括 Chrome、Firefox、Safari 和 Edge 在內(nèi)的主流瀏覽器的廣泛支持。不僅 Vue3 的更新就包括了對(duì) Web Components 的原生支持,現(xiàn)在面試也問 Web Components 話題,尤其是頻頻出現(xiàn) Shadow DOM

這項(xiàng)技術(shù)的魅力在于,它允許開發(fā)者創(chuàng)建自定義、可重用的元素,這些元素可以在任何符合標(biāo)準(zhǔn)的 Web 應(yīng)用中無縫使用,而不受限于特定的框架(React、Vue)。如果你還對(duì) Web Components 比較陌生,那么現(xiàn)在是時(shí)候開始了解這項(xiàng)技術(shù)了。

Web Components 核心概念

Web Components 是一種瀏覽器原生支持的 Web 組件化技術(shù),它允許開發(fā)者創(chuàng)建可重用的自定義元素,并且可以在任何支持 Web Components 的瀏覽器中使用。

image.png

Web Components 包括以下幾個(gè)核心概念:

  1. Custom Elements(自定義元素):允許開發(fā)者創(chuàng)建新的 HTML 元素,并且可以定義它的行為和樣式。
  2. Shadow DOM(影子 DOM):允許開發(fā)者封裝組件的內(nèi)部結(jié)構(gòu)和樣式,避免全局命名空間的污染。
  3. Templates(模板):允許開發(fā)者定義一個(gè)可以在多個(gè)組件中重用的 HTML 結(jié)構(gòu)。
  4. Slots(插槽):允許開發(fā)者創(chuàng)建一個(gè)可插入內(nèi)容的占位符,以便在不同的組件中使用。

今天將圍繞這 4 個(gè)核心概念以及相關(guān)拓展,通過例子演示重點(diǎn)說一下 Web Components 是如何創(chuàng)建可重用的自定義元素的。

Custom Elements(自定義元素)

Web Components 最大的特性之一就是能將 HTML 封裝成 Custom Elements(自定義元素)。下面我們通過一個(gè)簡(jiǎn)單的按鈕例子,看下它是怎么實(shí)現(xiàn)的。

創(chuàng)建自定義元素

首先,我們需要定義一個(gè)自定義元素。這可以通過使用 customElements.define() 方法來實(shí)現(xiàn)。在這個(gè)例子中,我們將創(chuàng)建一個(gè)名為 my-button 的自定義元素。

// main.js
class MyButton extends HTMLElement {
 constructor() {
   super();
   const shadowRoot = this.attachShadow({ mode: 'open' });
   shadowRoot.innerHTML = `
     <style>
       button {
         background-color: #4CAF50;
         border: none;
         color: white;
         text-align: center;
         text-decoration: none;
         display: inline-block;
         font-size: 16px;
         margin: 4px 2px;
         cursor: pointer;
         padding: 10px 24px;
         border-radius: 4px;
       }
     </style>
     <button>Click Me!</button>
   `
;
 }
}
customElements.define('my-button', MyButton);

現(xiàn)在我們已經(jīng)定義了一個(gè)名為 my-button 的自定義元素,我們可以在 HTML 文件中直接使用它。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Web Components Example</title>
</head>
<body>
 <my-button></my-button>

 <script src="./main.js"></script>
</body>
</html>

在這個(gè)例子中,我們創(chuàng)建了一個(gè)名為 my-button 的自定義元素,并在 HTML 文件中直接使用它。這個(gè)自定義元素將渲染為一個(gè)綠色的按鈕,上面寫著“Click Me!”。

不止如此,CustomElements 還支持自定義元素行為(如添加點(diǎn)擊事件),也就是說既能封裝 UI 樣式,也是封裝 UI 交互。

const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.querySelector('button').addEventListener('click', () => {
   alert('按鈕被點(diǎn)擊了!');
});

到這里為止,便實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的 Web Components,詳細(xì)代碼見CustomElements[1]

生命周期回調(diào)方法

Custom Elements 也有一組生命周期回調(diào)方法(到這里是不是感覺 Web Component 就像 Vue、React似得,怎么還有生命周期?),這些方法在元素的不同生命周期階段被調(diào)用。這些生命周期方法允許你在元素的創(chuàng)建、插入文檔、更新和刪除等時(shí)刻執(zhí)行操作。

以下是自定義元素的一些主要生命周期回調(diào)方法:

  1. constructor(): 構(gòu)造函數(shù),在創(chuàng)建元素實(shí)例時(shí)調(diào)用。適用于執(zhí)行初始化操作,例如設(shè)置初始屬性、添加事件監(jiān)聽器或創(chuàng)建 Shadow DOM。
  2. connectedCallback(): 當(dāng)自定義元素被插入到上下文時(shí)調(diào)用。適用于元素被插入到 DOM 時(shí)執(zhí)行的操作,例如獲取數(shù)據(jù)、渲染內(nèi)容或啟動(dòng)定時(shí)器。
  3. disconnectedCallback(): 當(dāng)自定義元素從文檔中移除時(shí)調(diào)用。適用于元素從 DOM 中移除時(shí)執(zhí)行的操作,例如移除事件監(jiān)聽器或停止定時(shí)器。
  4. attributeChangedCallback(attributeName, oldValue, newValue): 當(dāng)自定義元素的屬性被添加、移除或更改時(shí)調(diào)用。要使用這個(gè)回調(diào),你需要在類中定義一個(gè)靜態(tài)的 observedAttributes 屬性,列出你想要監(jiān)聽的屬性。

下面是一個(gè)簡(jiǎn)單的例子,展示了如何在自定義元素中使用這些生命周期方法:

class MyCustomElement extends HTMLElement {
 constructor() {
   super();
   // 初始化操作,例如創(chuàng)建 Shadow DOM
   const shadowRoot = this.attachShadow({ mode: 'open' });
   shadowRoot.innerHTML = '<p>這是一個(gè)自定義元素</p>';
 }
 connectedCallback() {
   // 元素被插入到 DOM 時(shí)執(zhí)行的操作
   console.log('Custom element connected to the DOM');
 }
 disconnectedCallback() {
   // 元素從 DOM 中移除時(shí)執(zhí)行的操作
   console.log('Custom element disconnected from the DOM');
 }
 attributeChangedCallback(name, oldValue, newValue) {
   // 監(jiān)聽的屬性發(fā)生變化時(shí)執(zhí)行的操作
   console.log(`Attribute ${name} changed from ${oldValue} to ${newValue}`);
 }
 staticget observedAttributes() {
   // 返回一個(gè)數(shù)組,包含需要監(jiān)聽的屬性
   return ['my-attribute'];
 }
}
customElements.define('my-custom-element', MyCustomElement);

在 HTML 中使用這個(gè)自定義元素:

<my-custom-element my-attribute="value"></my-custom-element>

當(dāng) my-custom-element 被插入到 DOM 中時(shí),connectedCallback 會(huì)被調(diào)用。如果元素被從 DOM 中移除,disconnectedCallback 會(huì)被調(diào)用。如果元素的 my-attribute 屬性發(fā)生變化,attributeChangedCallback 會(huì)被調(diào)用。

注意:監(jiān)聽的同時(shí),也記得停止監(jiān)聽。比如說你可能需要在元素連接到 DOM 時(shí)開始監(jiān)聽事件,但是在元素?cái)嚅_連接時(shí)停止監(jiān)聽,避免內(nèi)存泄漏。

Shadow DOM(影子 DOM)

下面我們將繼續(xù)探討 Shadow DOM,它是 Web Components 的核心特性之一。

Shadow DOM

Shadow DOM 允許開發(fā)者創(chuàng)建一個(gè)封閉的 DOM 子樹,這個(gè)子樹與主文檔的 DOM 分離,這意味著 Shadow DOM 內(nèi)部的樣式和結(jié)構(gòu)不會(huì)受到外部的影響,也不會(huì)影響到外部。

在“Custom Elements(自定義元素)”的例子中,我們已經(jīng)簡(jiǎn)單使用了 Shadow DOM。

1、使用 innerHTML

通過設(shè)置 Shadow DOM 的 innerHTML 屬性,可以直接添加一個(gè)或多個(gè)元素。這種方式適用于從字符串模板快速填充 Shadow DOM。

class MyElementInnerHTML extends HTMLElement {
 constructor() {
   super();
   const shadowRoot = this.attachShadow({ mode: 'open' });
   shadowRoot.innerHTML = `
     <style>
       p { color: black; }
     </style>
     <p>使用 innerHTML</p>
   `
;
 }
}
customElements.define('my-element-inner', MyElementInnerHTML);

2、使用 createElement 和 appendChild

也可以使用 document.createElement 方法創(chuàng)建一個(gè)新元素,然后使用 appendChild 方法將其添加到 Shadow DOM 中。

const wrapper = document.createElement('p');
wrapper.textContent = '使用 createElement 和 appendChild';

var style = document.createElement('style');
style.textContent = `
p { color: gray; }
`
;
// 引入外部樣式同樣可以使用 appendChild
// const linkElement = document.createElement('link');
// linkElement.setAttribute('rel', 'stylesheet');
// linkElement.setAttribute('href', 'style.css');
class MyElementAppend extends HTMLElement {
 constructor() {
   super();
   const shadowRoot = this.attachShadow({ mode: 'open' });

   shadowRoot.appendChild(wrapper);
   shadowRoot.appendChild(style);
   // shadowRoot.appendChild(linkElement);
 }
}
customElements.define('my-element-append', MyElementAppend);

3、template 方式

除上面兩種方式外,還可以使用模板元素 (<template>)添加,具體見下方 “Templates(模版)”

Shadow Mode

其中在自定義元素的構(gòu)造函數(shù)中,我們調(diào)用了 attachShadow() 方法,并傳入了一個(gè)對(duì)象 { mode: 'open' }。這里的 mode 屬性決定了 Shadow DOM 的封裝模式,它有兩個(gè)可能的值:

  • open:允許外部訪問 Shadow DOM 的 API。
  • closed:不允許外部訪問 Shadow DOM 的 API。

在這個(gè)例子中,我們創(chuàng)建了一個(gè) Shadow DOM,并向其中添加了一行文字和相關(guān)的樣式。由于 Shadow DOM 的封裝性,這些樣式只會(huì)在 my-element 元素內(nèi)部生效,不會(huì)影響到頁面上的其他元素(樣式隔離)。

下面我們更詳細(xì)地探討 Shadow DOM 是否允許外部訪問,的兩種封裝模式:open 和 closed

1、Shadow Mode:open 模式

當(dāng)使用 open 模式創(chuàng)建 Shadow DOM 時(shí),外部腳本可以通過 Element.shadowRoot 屬性訪問 Shadow DOM 的根節(jié)點(diǎn)。

這意味著你可以從外部查詢、修改 Shadow DOM 內(nèi)部的元素和樣式。下面是一個(gè)使用 open 模式的例子:

class OpenMyElement extends HTMLElement {
 constructor() {
   super();
   // 創(chuàng)建一個(gè) open 模式的 Shadow DOM
   const shadowRoot = this.attachShadow({ mode: 'open' });
   shadowRoot.innerHTML = `
     <style>
       p { color: red; }
     </style>
     <p>這是一個(gè) open 模式的 Shadow DOM</p>
   `
;
 }
}
customElements.define('open-my-element', OpenMyElement);

// 在外部訪問 Shadow DOM
const element = document.querySelector('open-my-element');
console.log(element.shadowRoot); // 輸出 ShadowRoot 對(duì)象

在這個(gè)例子中,我們創(chuàng)建了一個(gè)自定義元素 open-my-element,它有一個(gè) open 模式的 Shadow DOM。由于模式是 open,我們可以在外部通過 element.shadowRoot 訪問 Shadow DOM 的根節(jié)點(diǎn),并進(jìn)行進(jìn)一步的操作,比如添加或刪除子元素,修改樣式等。

image.png

2、Shadow Mode:closed 模式

當(dāng)使用 closed 模式創(chuàng)建 Shadow DOM 時(shí),外部腳本無法通過 Element.shadowRoot 屬性訪問 Shadow DOM 的根節(jié)點(diǎn)。

這意味著 Shadow DOM 內(nèi)部的元素和樣式對(duì)外部是完全隱藏的,無法從外部直接訪問或修改。 下面是一個(gè)使用 closed 模式的例子:

class ClosedMyElement extends HTMLElement {
 constructor() {
   super();
   // 創(chuàng)建一個(gè) closed 模式的 Shadow DOM
   const shadowRoot = this.attachShadow({ mode: 'closed' });
   shadowRoot.innerHTML = `
     <style>
       p { color: blue; }
     </style>
     <p>這是一個(gè) closed 模式的 Shadow DOM</p>
   `
;
 }
}
customElements.define('closed-my-element', ClosedMyElement);

// 在外部嘗試訪問 Shadow DOM
const element = document.querySelector('closed-my-element');
console.log(element.shadowRoot); // 輸出 null

在這個(gè)例子中,我們創(chuàng)建了一個(gè)自定義元素 closed-mode-element,它有一個(gè) closed 模式的 Shadow DOM。由于模式是 closed,當(dāng)我們嘗試在外部通過 element.shadowRoot 訪問 Shadow DOM 的根節(jié)點(diǎn)時(shí),將得到 null

image.png

open 和 closed 模式?jīng)Q定了 Shadow DOM 的封裝程度:

  • open 模式允許外部訪問 Shadow DOM 的 API,這意味著你可以從外部查詢和修改 Shadow DOM 內(nèi)部的元素和樣式。
  • closed 模式不允許外部訪問 Shadow DOM 的 API,這意味著 Shadow DOM 內(nèi)部的元素和樣式對(duì)外部是完全隱藏的,無法從外部直接訪問或修改。

選擇哪種模式取決于你的具體需求。如果你希望組件的內(nèi)部結(jié)構(gòu)和樣式完全對(duì)外部隱藏,使用 closed 模式是更好的選擇。如果你需要從外部訪問和修改組件的內(nèi)部結(jié)構(gòu)和樣式,使用 open 模式會(huì)更合適。

完整代碼,詳見ShadowDOM[2]

其外,Shadow DOM 還支持更高級(jí)的用法,比如可以將 Shadow DOM 分割成多個(gè) Shadow Trees,使用 slots(插槽)來插入內(nèi)容,以及使用 template(模板)來定義可重用的 HTML 結(jié)構(gòu)。

Slots(插槽)

Slots 是一種特殊類型的元素,它允許你將內(nèi)容從組件的一個(gè)部分傳遞到另一個(gè)部分,增加了組件的靈活性。它使得 Web Components 自定義元素,更加的靈活。

基礎(chǔ)使用

例如,我們可以修改 my-button 組件,使其允許用戶自定義按鈕文本:

class MyButton extends HTMLElement {
 constructor() {
   super();
   const shadowRoot = this.attachShadow({ mode: 'open' });
   shadowRoot.innerHTML = `
     <style>
       /* ...樣式代碼保持不變... */
     </style>
     <button>
         <slot>Click Me!</slot>
     </button>
   `
;
 }
}
customElements.define('my-button', MyButton);

現(xiàn)在,當(dāng)我們?cè)?HTML 中使用 my-button 時(shí),我們可以向其中插入任何內(nèi)容,它會(huì)替換掉 <slot> 標(biāo)簽:

<my-button>Slots Custom Text</my-button>

image.png

命名插槽

在開發(fā)中,我們更多的還會(huì)遇到不同情況下,選擇插入的內(nèi)容,這里就用到了命名插槽,使用起來非常方便。

class MyButtonName extends HTMLElement {
 constructor() {
   super();
   const shadowRoot = this.attachShadow({ mode: 'open' });
   shadowRoot.innerHTML = `
     <style>
       /* ...樣式代碼保持不變... */
     </style>
     <button>
       <slot name="element-name"></slot>
       <slot name="element-age"></slot>
       <slot name="element-email"></slot>
     </button>
   `
;
 }
}
customElements.define('my-button-name', MyButtonName);
<my-button-name>
   <span slot="element-name">element-name</span>
</my-button-name>
<my-button-name>
   <span slot="element-age">element-age</span>
</my-button-name>
<my-button-name>
   <span slot="element-email">element-email</span>
</my-button-name>

image.png

是不是很方便,很靈活!!具體代碼詳見Web Components Slots[3]

Templates(模板)

Templates 允許你定義一個(gè)可以在多個(gè)組件中重用的 HTML 結(jié)構(gòu)。你可以將模板放在 HTML 文件中的任何位置,并通過 JavaScript 動(dòng)態(tài)地實(shí)例化它們:

<my-button></my-button>

<template id="my-button-template">
 <style>
   /* ...樣式代碼保持不變... */
 
</style>
 <button>
     <slot>Click Me!</slot>
 </button>
</template>

在 JavaScript 中,你可以這樣使用模板:

class MyButton extends HTMLElement {
 constructor() {
   super();
   const shadowRoot = this.attachShadow({ mode: 'open' });
   const template = document.getElementById('my-button-template');
   // 使用`cloneNode()` 方法添加了拷貝到 Shadow root 根節(jié)點(diǎn)上。
   shadowRoot.appendChild(template.content.cloneNode(true));
 }
}
customElements.define('my-button', MyButton);

image.png

這樣,你就可以在不同的組件中重用同一個(gè)模板,從而提高代碼的可維護(hù)性和重用性。具體代碼下詳見Web Components Templates[4]

相關(guān)拓展

Web Components 兼容性

Web Components 是一組用于構(gòu)建可復(fù)用組件的技術(shù),包括 Custom Elements, Shadow DOM, HTML Templates 等。這些技術(shù)的出現(xiàn),使得開發(fā)者能夠更好地組織,去開發(fā)復(fù)雜的網(wǎng)頁應(yīng)用。然而,由于這些技術(shù)相對(duì)較新,不同瀏覽器的支持情況不盡相同,因此兼容性問題也是我們需要重點(diǎn)關(guān)注的方向。

Custom Elements

image.png

Shadow DOM

image.png

HTML Templates

image.png

從上面可以看出,現(xiàn)階段市場(chǎng)上大部分的瀏覽器已經(jīng)都原生支持了 Web Components 的規(guī)范標(biāo)準(zhǔn)。但是如果說出現(xiàn)了兼容性問題,我們應(yīng)該怎么處理?

Polyfills

對(duì)于舊版瀏覽器不支持的兼容性情況,可以考慮使用 polyfill 來實(shí)現(xiàn)兼容性。Polyfills 是一種代碼注入技術(shù),使得瀏覽器可以支持新的標(biāo)準(zhǔn) API。對(duì)于不支持 Web Components 的瀏覽器,我們可以用 Polyfills 讓這些瀏覽器可以支持 Web Components。

這里我們可以用到 webcomponents.js[5] 庫,它可以實(shí)現(xiàn)兼容 Custom Elements、Shadow DOM 和 HTML Templates 標(biāo)準(zhǔn),讓我們?cè)陂_發(fā)時(shí)不必考慮兼容性問題。

npm install @webcomponents/webcomponentsjs
<!-- load webcomponents bundle, which includes all the necessary polyfills -->
<script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>

<!-- load the element -->
<script type="module" src="my-element.js"></script>

<!-- use the element -->
<my-element></my-element>

具體配置詳情,見polyfills webcomponents[6]

React 與 Vue

相信大家也比較關(guān)心 Web Components 與現(xiàn)有框架(如 React、Vue)相比有哪些優(yōu)勢(shì)?以及各自適用場(chǎng)景?

首先,Web Components 是一組 Web 平臺(tái) API,允許開發(fā)者創(chuàng)建可重用的自定義元素,而無需依賴于任何特定的框架。與現(xiàn)有的前端框架,Web Components 有以下幾個(gè)優(yōu)勢(shì):

  1. 標(biāo)準(zhǔn)化:Web Components 是基于 Web 標(biāo)準(zhǔn)(如 Custom Elements、Shadow DOM 和 HTML Templates)構(gòu)建的,這意味著它們得到了瀏覽器廠商的直接支持,而不依賴于任何特定的庫或框架。
  2. 輕量級(jí):Web Components 不需要額外的庫或框架即可工作,這可以減少應(yīng)用程序的依賴性和大小,特別是在不需要框架其他功能的情況下。
  3. 封裝性:通過 Shadow DOM,Web Components 可以將標(biāo)記結(jié)構(gòu)、樣式和腳本封裝在一起,避免全局樣式和腳本的沖突,保證了組件的獨(dú)立性和重用性。
  4. 易于集成:Web Components 可以與現(xiàn)有的框架(如 React 和 Vue)集成,開發(fā)者可以在這些框架中使用 Web Components,或者將現(xiàn)有的框架組件封裝成 Web Components 以供其他項(xiàng)目使用。

然而,Web Components 也有其局限性,例如:

  • 生態(tài)系統(tǒng):與 React 和 Vue 等成熟框架相比,Web Components 的生態(tài)系統(tǒng)較小,社區(qū)支持和資源可能不如這些框架豐富。
  • 功能限制:Web Components 本身不提供狀態(tài)管理、路由等高級(jí)功能,這些通常需要額外的庫或框架來實(shí)現(xiàn)。
  • 性能:對(duì)于復(fù)雜的應(yīng)用程序,一些框架(如 React)通過虛擬 DOM 等技術(shù)提供了更高的性能優(yōu)化,而 Web Components 需要開發(fā)者手動(dòng)優(yōu)化。

總的來說,Web Components 提供了一種標(biāo)準(zhǔn)化且框架無關(guān)的方式來構(gòu)建組件,適合組件庫的開發(fā)。而框架如 React、Vue 則在生態(tài)系統(tǒng)支持、開發(fā)體驗(yàn)和數(shù)據(jù)處理方面有明顯優(yōu)勢(shì),適合快速開發(fā)復(fù)雜的應(yīng)用程序

實(shí)際應(yīng)用案例

  1. Vue3: Vue3 引入了對(duì) Web Components 的原生支持,通過所謂的 “Vue Components”,它允許將 Vue 組件轉(zhuǎn)換為 Web Components。
  2. MicroApp[7]:基于 Web Components 的一款簡(jiǎn)約、高效、功能強(qiáng)大的微前端框架。
  3. Twitter[8]:Twitter 2016 年開始將自己的嵌入式推文   從 iframe 切換成  ShadowDOM,減少了內(nèi)存消耗、加快了渲染速度,并批量渲染的時(shí)候保持絲滑。
  4. svelte + vite 開發(fā) Web Components[9]:通過 svelte + vite 快速搭建 web components 的項(xiàng)目。
  5. 使用 Polymer 構(gòu)建 Web Components[10]:用于構(gòu)建 Web Component,它提供了一套工具和 API,能夠更容易地創(chuàng)建自定義元素。

參考資料

  1. **MDN Web Docs - Web Components 入門**[11]
  2. 你不知道的 Web Components - 現(xiàn)狀[12]
  3. 自定義元素 v1 - 可重復(fù)使用的網(wǎng)絡(luò)組件[13]
  4. Web Components Tutorial for Beginners \[2019\][14]

總結(jié)

Web Components 是 W3C 推動(dòng)的標(biāo)準(zhǔn)化技術(shù),它通過自定義元素的方式,允許開發(fā)者在瀏覽器中直接使用。這種技術(shù)通過 Shadow DOM 實(shí)現(xiàn)了組件化 DOM 隔離和樣式隔離,確保了組件的獨(dú)立性和可重用性,這些特性被現(xiàn)有很多借鑒和使用。


該文章在 2024/3/27 16:37:49 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲(chǔ)管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
偷拍亚洲第一成年网站 | 在线中文字幕永久在线 | 亚洲国产成在线网站91 | 一级a爱视频日本免费 | 未满成年国产在线观看 | 午夜成本人动漫在线观看 |