整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          字節(jié)跳動的微前端沙盒實踐

          文以字節(jié)跳動的微前端項目運行時隔離任務(wù)出發(fā),深入講解 sandbox (后稱沙盒)的技術(shù)實現(xiàn),以及上述實際實現(xiàn)過程中一些發(fā)生過的問題。把一些關(guān)鍵細節(jié)和多年的采坑經(jīng)驗充分的分享給讀者,希望能對大家有一些幫助和啟發(fā)。至于對微前端的整體思考,可以參考:《前端微服務(wù)在字節(jié)跳動的打磨與應(yīng)用》,希望讀者在讀本文之前已經(jīng)有所了解。



          1. 沙盒應(yīng)該做什么

          首先從沙盒對微前端乃至前端的意義開始講起。沙盒對軟件工程來說其概念不算是新鮮事物,僅看前端對隔離的需求也由來已久。并且根據(jù)不同的實際業(yè)務(wù)場景,已經(jīng)有過非常多和有特色的探索。

          古老的 Iframe

          一切都從 iframe 開始講起了,反正是個看上去很美的解決方案。沒有真的用過的人肯定都會這樣想象。但有些可能等到你要真的搞一個通過 iframe 全面聚合的才知道。單純的 iframe 聚合非常麻煩,需要很多補漏的勞動量。

          舊的 iframe 的方案可以在一定程度上解決了耦合問題。具體是把一個站點頁面拆成 N 個 frame,每個 frame 單獨跑一個獨立的域名。

          它的好處非常清楚,獨立上下,獨立運行,誰都不會妨礙誰。但是是不是這樣沙盒就完成了呢?這樣算不算沙盒就不好說了,會有很多不同的觀點和理論。比如一些觀點可能會覺得沙盒不是像這樣全獨立,而是以隔離模擬獨立。后面我們會再次談到這個觀點,并從實現(xiàn)角度分享一些我們的思考成果。

          因為一個完整的項目包含大量公用的功能和代碼,例如登錄身份、站內(nèi)信,業(yè)務(wù)模塊只是其中的一個部分。這部分完全用跨 window 通信實現(xiàn)起來很費時費力,并且單頁應(yīng)用了 React 或類似的加載技術(shù)展示之后,iframe 的效果也遜色很多。想要突破這些限制,困難就很多了。

          古老的困難

          第一點不用多說各位都會想到 deeplinking 的問題,對吧,至少這點得做到才能算是一個工程,尤其 MVC 時代以來路由一直非常重要。

          還有就是各種共享的東西,比如登錄怎么共享。iframe 當(dāng)然也不是不行。和前面后面提到的諸多問題一樣都不是不行、而是很麻煩,要針對他去解決很多困難。從效果上講,最終也完全可以形成一個不錯的 iframe 沙盒。

          另一顯然的困難是,組件庫、組件風(fēng)格的父子傳遞,以及 React VUE 等渲染引擎的底層代碼、內(nèi)存對象的傳遞。初步的實現(xiàn)是加入分片打包功能,拆 common chunk 并獨立部署 CDN 上,最后在加載時,通過瀏覽器自身的緩存能力加速訪問。但是運行時內(nèi)存并不共享,對包的運行時修改也難以復(fù)用。

          還有數(shù)據(jù)層的設(shè)計,數(shù)據(jù) Store 等等。數(shù)據(jù)層至少要有一定的事件打通的功能。搞不好就牽一發(fā)動全身,改一個需求,不得不發(fā)布四五個項目。

          2. 沙盒應(yīng)該像什么

          前面提到過我們不希望沙盒是完全獨立的運行時環(huán)境,而是有分享和協(xié)同的可靠環(huán)境。這一章我們希望能說清我們希望沙盒提供怎樣的功能、如何使用。

          虛擬化、容器化、Docker

          到這里開始講到美好的景物了,docker。從解耦的角度看,服務(wù)端的微服務(wù)主要是通過 docker 技術(shù)實現(xiàn)虛擬化的底層支持,使服務(wù)開發(fā)者可以體會不到環(huán)境的區(qū)別、抹平運行時差異的。可以說對微服務(wù)來說,docker 是這些年能得到如此的發(fā)展的一個基石。

          單純說微服務(wù)的概念本身,很久之前也有這個概念的,有面向服務(wù)編程的理論。但是發(fā)展很少,兌現(xiàn)仍然很困難,搞虛擬機很麻煩。而且還包括開發(fā)體驗的東西,我打包的鏡像——要想交付一致得包含整個操作系統(tǒng)嗎?這對開發(fā)體驗影響很壞。

          在 docker 得到普遍應(yīng)用之前,微服務(wù)在服務(wù)端的使用主要基于虛機。相比之下使用非常復(fù)雜、維護成本提高。虛擬機不說多麻煩了,大家都懂。它吃掉的資源,和容器化技術(shù)比完全不在一個量級。還有比如當(dāng)你想要打個快照連磁盤都吃掉。并且多個服務(wù)之間的資源協(xié)調(diào)和有效分配,實現(xiàn)起來也極端困難。

          諸多擴大的成本問題直到隨著 docker 的沙盒體系才得以解決。微服務(wù)才成為一個趨勢。可惜的是這樣的容器環(huán)境在前端瀏覽器內(nèi)的運行時還不存在。

          所以這里已經(jīng)可以看出我們提出的前端沙盒、對它的期望,是讓它就像 Docker(而 iframe 在這個比喻里就相當(dāng)于虛擬機)那樣。我們搞的這套機制是像 Docker 的前端運行時容器,像 Docker 一樣讓前端的拆分能輕松一點、分享容易一點、資源節(jié)約一點。當(dāng)然這不是否定 iframe 的方案。

          3. 沙盒應(yīng)該怎么做

          那么我們說的這種沙盒,這種輕量級、強調(diào)組件間協(xié)同溝通、非常節(jié)省資源的沙盒怎么做呢,下面我分 3 個方向分別介紹。(這塊還不會有具體的實現(xiàn),主要從可能性上分析在瀏覽器里怎么造沙盒。)

          3.1 單進程與多進程

          參考單核、操作系統(tǒng)進程,模擬進程切換策略。 我們的沙盒實質(zhì)上在讓一個瀏覽器去跑多個“獨立”的應(yīng)用,那么這里對操作系統(tǒng)的模仿、最終趨同一定避不開。在這個角度上,和其他語言相比 JavaScript 占了一個獨特的執(zhí)行特點的便宜:它自身是單線程的。我怎么做實質(zhì)上也都是在一個線程內(nèi)。相當(dāng)于我們這個操作系統(tǒng)從一開始就限定了單核只有一個出力氣。

          那么一個操作系統(tǒng),怎么做多進程并行呢, 單進程可簡單通過根路由等等規(guī)則控制,每次只激活一個,大家做 context 切換即可;多進程并行就正好可以利用 JavaScript 的特性,我可以封裝每個獨立的事件循環(huán)。比如 setTimeout、各種事件回調(diào)的 handler,我們在實際 function 外面先切換 context,再執(zhí)行你原本希望綁定的 function。這樣是線程安全的。總結(jié)下來就會是下面兩條:

          1. 用路由切換封裝,模擬單核單進程。
          2. 用事件循環(huán)的總體封裝,模擬單核多進程。

          3.2 Context 切換

          用 context 切換來模擬線程安全, 具體的意思是在每個隔離的子應(yīng)用“進程”即將開始激活時,先查找當(dāng)前被激活的、其他的子應(yīng)用,然后為這個將要退出的應(yīng)用錄制“操作系統(tǒng)”的全現(xiàn)場狀態(tài),保存為它的 context。最后為即將激活的新“進程”恢復(fù)、新建它自己的 context。

          如上面所說,我把當(dāng)前狀態(tài)記錄為 context,保證每個子應(yīng)用都適用在自己的 context 內(nèi),不影響和改變別人的 context。這個操作全部由托管了子應(yīng)用的父系統(tǒng)統(tǒng)一來切換。

          本次重點講落地實踐,和一些踩坑經(jīng)驗。歡迎大家持續(xù)關(guān)注,我們會輸出更多關(guān)于這部分的實踐經(jīng)驗。

          體現(xiàn)刪除 key 必須要遍歷兩次, 才能保證每個對象都遍歷到一遍。這塊要強調(diào)一個點,當(dāng)你拿到新舊兩個對象比較,遍歷其中一個的 key、到另一個里面找,只這樣做是不夠的,因為有可能又刪掉的東西。刪掉導(dǎo)致 key 沒有了,自然也遍歷不到。想體現(xiàn)這個刪除,必須要遍歷兩次,新舊兩個對象都遍歷一遍,才能知道相比之下誰多了什么誰少了什么。尤其是大家做“空閑”到新開沙盒的比較的時候,特別容易忘了這個細節(jié)。

          Context 切換的性能夠好嗎? 先說說這個快照的空間性能。如果你有 N 個沙盒需要有多少切換的組合呢,是不是 context 的全文、或者任意兩個沙盒之間的 context 差異都要完整儲存?實際上不用。我們只需要記錄差別、context 的變化,并且只記錄他對 “idle”狀態(tài)的差別。例如 A、B、C、D、E、F、G。我們不需要記錄 A→B A→C 這樣的切換,而是虛擬一個空閑狀態(tài):O,都是 A→O,B→O,只保存他們和 O 之間的差別。需要記錄比較的變量數(shù)量從子應(yīng)用個數(shù)的乘法變成了加法。寫一個循環(huán)就可以快速比較完變化。

          綜上所述就是讓每個子應(yīng)用的開始和結(jié)束、互相切換,都先回到一個虛擬的“初始狀態(tài)”,恢復(fù)現(xiàn)場,再進入被激活的沙盒狀態(tài),每次切換僅記錄一個沙盒信息。避免了切換算法計算笛卡爾平方積導(dǎo)致比較、和保存沙盒切換信息過大的問題。

          4. 字節(jié)跳動的沙盒采取的方案

          雖然這個章節(jié)的名字是字節(jié)跳動的實現(xiàn),并且前面提到這次我們主要分享實現(xiàn)層面的技術(shù)細節(jié),但我們不會僅僅探討和分享自己落地采用的方案,探討的內(nèi)容也會包括研究過和對比過的。如果我們認為有好的、適合其他場景的技術(shù)方案,我們也都盡量分享出來。

          4.1 CSS 沙盒

          先說 CSS 沙盒。 這塊 webComponent 已經(jīng)做了很多發(fā)展了很多了。這里忍不住要說,web 標準里一度有一個非常吸引我、讓我感覺非常有意思的內(nèi)容是 scoped css——就是加個 Attribute 就能結(jié)合 DOM 樹限制 CSS 作用范圍。后來這個標準被取消了。因為讓路給了 ShadowDOM 體系。

          這個我不是很理解:因為 scoped CSS 是外面的規(guī)則能進來、里面的規(guī)則不出去,但 shadowDOM 是完全的割裂。這個巨大的區(qū)別使得它們的工程意義相差甚遠。后面我們會說到 css module,它的表現(xiàn)顯然和 scoped style 一樣,和 Shadow 不一樣。

          CSS module 和 CSS in JS 都是把樣式寫成或編譯成腳本,同時把腳本生成的 DOM 的最外面一層加一個 nounce 的 attribute;然后再給所有受控的 CSS 規(guī)則都套上這個 "attribute"。缺點是相對麻煩了一點、并且要完全控制掌握所有 DOM 創(chuàng)建。在前端框架里,Angular 這樣做很自然。

          后面還會提到這方面最流行的 NPM 包有個好玩的 feature 可能會造成不小心的 bug。

          我們采用的是 DOM 沙盒保護 head 內(nèi)標簽。 這樣的 style 和 link 本身都可以受到沙盒統(tǒng)一保護。在實際應(yīng)用中我們的子應(yīng)用開發(fā)者在業(yè)務(wù)組件里也有用 CSS module 的,我們也不用管——反正去掉標簽這個事情最安全。

          DOM 沙盒就看管好某個 DOM 標簽,誰要改了,沙盒切換時改回來。對絕大多數(shù)情況綁定的 style 和 link 標簽都有效。但這個只限于單進程的情景。

          如果如前面提到的多進程的情況(就是理解成同時有 N 個沙盒在一起運行、并行的系統(tǒng))。那 CSS 肯定不能和 JavaScript 的單線程運行時一樣那么搞,所以一定要用 moduled CSS。也不難搞,很多開源庫可以用。即使出現(xiàn)大家引用同一個組件庫的不同版本、各自 hack 過、失手創(chuàng)造了什么“幺蛾子”也不用怕,因為他們都是編譯好、作用域有限了的。

          用 NPM 上的 styled-component 包時要小心, 他們會根據(jù)環(huán)境變量判斷環(huán)境;然后對 prod 環(huán)境啟用一個叫“speedy”的模式,它將不用 innerText 寫樣式規(guī)則,而是用 addRules 那一整套 API。但是這套標準似乎沒明確界定這個標簽被從文檔 DOM 樹里移除時的行為和表現(xiàn),也許因為顯而易見 rules 也應(yīng)當(dāng)一起移除。但我們插回來時,這種含糊就亂套了。瀏覽器實際的表現(xiàn)是移除再插回的標簽 rules 都沒了。這里顯然需要我們額外處理。

          4.2 全局變量沙盒

          另一個重要的是全局變量干擾問題。 Polyfill 等運行環(huán)境相關(guān)的全局對象、環(huán)境變量等具體實現(xiàn)上有非常大的差別,又全部作用于全局。它們對子應(yīng)用、模塊化的子組件來說,又屬于自身全局外部的環(huán)境。

          這塊是微前端實施的一大重點。我個人覺得是這樣的。可以看出來大家都不是很信。“誰不知道不要寫全局變量啊?不會有這么不靠譜的人”。事實上真的試過才會發(fā)現(xiàn)會有好多。例如頭條號里面用到了某個剪裁圖片的插件庫。他是個非常完善、正派、和古典的包,同時支持 React 和 JQuery。它給全局寫了一個單例的實現(xiàn)。并且在開發(fā)調(diào)試過程中我們不同業(yè)務(wù)線的團隊就真的用了這個包的不同版本。

          當(dāng)然這個不重要,也沒有造成問題。一個比較嚴峻的例子是這個—— reGeneratorRuntime。它是編譯 async 語法用的,在某個 config 下的 Babel 會 delete 這個對象。到底是啥原理不清楚也不需要多講,但是非常肯定會沖突并造成問題。曾經(jīng)我們的西瓜號團隊的 polyfill 規(guī)則和另一個業(yè)務(wù)線就發(fā)生了這類沖突。所以要比較 delete,恢復(fù)刪除,切換回去西瓜再刪掉。

          Identifier 是另一個關(guān)注點。 你是否完全清楚 Identifier 是什么?Identifier 就是在某個 scope 下起作用的變量名啊什么的,包括 function,let,class,const。只有 var 出來的東西特殊一些、不會占用 Identifier,以上幾個會,占用后不可以重復(fù)用。

          這些東西首先你遍歷不了,沒有枚舉器;其次他們不是某個對象的成員,而僅是編譯層面的名字。一旦產(chǎn)生了絕對刪不掉。

          在全局作用域下 var a 的時候,實際上是生成了一個超范圍的 Identifier 并且額外在 global 上創(chuàng)建一個同名的 key,指向同一個地址。這是 var 語句額外的操作。這讓我們可以用遍歷 window 的方式來處置全局變量。

          但如果你來個 const 就沒辦法了,沒有任何辦法。 class 也一樣。沒辦法枚舉也沒辦法刪除。最多就是再用 class 關(guān)鍵字聲明一下覆蓋掉。

          總之這個事不要多想,new function 包起來幾乎必不可少。還可以傳入如 setTimeout 這種入?yún)ⅲ脕砜刂飘惒綄崿F(xiàn)“多進程”并行。

          還有個 location 不要挪, 會刷新頁面。黑名單掉它。

          還有個好玩的事:function 和 var 一樣會額外在 window 上增加個 key。這個 property 的 configurable 是 false——也就是不能刪除。但是可以賦值。

          所以如果你如果光 var a,就可以 delete window.a;再寫 a 就是 undefined。寫個 function a,再寫個 delete a 就無效。 但如果你寫個 function a,再寫個 var a = 1。啥效果呢,你給 window 上綁了個刪不掉的數(shù)字,延續(xù)了 function a 的不可刪除屬性和 var a 的值。

          更好玩的是 class,你 class B {} ,再 console log window.B,咋么樣,undefind。再寫 B = 1;然后再看 window.B 怎么樣?繼續(xù) undefined 了, B = 1 沒有效果。

          說明潛在的某個機制在 class 關(guān)鍵字執(zhí)行的時候,給 global 綁上了個叫 B 的 property,但是是個無法枚舉和訪問的 property,property 有 writable true, enumerable: true, configurable: true 之外的隱藏屬性。

          4.3 其他

          還有好多需要進程安全的對象, 比如 cookie,但這個其實不特別重要,簡單約定一個使用 path 就可以了——cookie 除了設(shè)置 domain 還可以設(shè)置 path。只不過大部分人都不設(shè)它(也就是設(shè)為根目錄“/”)。

          localStorage 可以也保護一下。 取決于你的業(yè)務(wù)。因為這些都屬于 windows 的全局變量,所以實現(xiàn)一個包裝過的 class 集成并模擬 localStorage 原本的行為就可以。讓它所有方法都先給 key 加 prefix,再執(zhí)行方法的 super。這個 prefix 可以簡單地寫死當(dāng)前沙盒的 uuid 即可,因為 window.localStorage 作為全局變量本身就在沙盒保護之內(nèi)。

          5. 沙盒的其他功能

          下面是最后一章節(jié),會講沙盒下有些特殊的東西,它們都需要額外處理。其中重點說一下埋點。多數(shù)微前端項目一個頁面里的埋點已經(jīng)屬于不同項目了,這塊就得搞清楚具體什么子應(yīng)用、用的什么統(tǒng)計代碼、需要處理哪些級別的緩存。

          5.1 埋點緩存系統(tǒng)

          像前面說的,把 Storage 緩存全部用沙盒包裝過,對埋點體系來說還不算完。絕大多數(shù)埋點系統(tǒng)的事件發(fā)送都是異步、找網(wǎng)絡(luò)空閑的。并且這些源碼通常又在 SDK 里面、不在父工程直接控制的代碼里。所以可操作余地不多。實際上只能是把緩存數(shù)據(jù)、項目信息都好好保存好,再把收集數(shù)據(jù)的緩存和產(chǎn)生數(shù)據(jù)時的沙盒狀態(tài)對應(yīng)起來。

          5.2 console

          沙盒可能會包一層或者多層運行時,所以 console 讀會比較累。開發(fā)的時候可以額外處理一下,為開發(fā)者提供便利。 而且現(xiàn)在的前端項目,線上希望 console 打印越少越好、內(nèi)容越正規(guī)越好,并且調(diào)試又非常忌諱別人遺留的打印干擾。這些都是沙盒可以做的。我們甚至做了把內(nèi)容直接對接到采集系統(tǒng)里的上傳 log。

          具體來說,為 log 注入 callstack 是用 new Error 的方式。這樣可以通過 error.stack 拿到調(diào)用堆棧。這個值直接是個字符串、是換行分割的 Markdown,可以寫鏈接進去,也能對應(yīng)到調(diào)試窗口的 source code。

          同理的是當(dāng)遇到真的 exception 也應(yīng)當(dāng)如此管控。從 catch 到異常、再次 throw 出去之前,可以給 error.stack 值全都 hack 掉。去掉不必要的 stack——比如你包的那層 new Function,刪掉那一行。提示的內(nèi)容也可以改。

          5.3 sourceMapping

          sourceMapping 是谷歌 closure 發(fā)明的一個、現(xiàn)在成為 ES6 標準的東西。原理是一個字符位置到字符位置的映射。那么在 new Function 下的沙盒里能不能用呢?當(dāng)然可以。

          我們先說說 new Function 的表現(xiàn)。在 chrome 里它在調(diào)試中是一個新的匿名環(huán)境:anonymous,字符行列位置就從函數(shù)字符串開頭第一行開始算起。如果你是把編譯并且生成了 sourceMap 后的 bundle 放到 new function 里執(zhí)行,這個位置是完全對應(yīng)的,不需要做任何額外的 hack。

          這同時是因為 chrome 能正常識別 new Function 參數(shù)字符串末尾的 sourcemappingUrl= 的注釋。對應(yīng)在 callstack 里一切都對。有好多時候我們發(fā)現(xiàn)業(yè)務(wù)方會不放心這個事,會覺得我直接下載的 .js 被包了,不放心調(diào)試的 call stack 和 sourceMap。事實上沒問題。這兩方面都沒問題。

          另外我們之前其他場合分享也提到了,我們認為微前端的諸多必備條件,其中一個是要有一個服務(wù)發(fā)現(xiàn)資源和版本管理平臺,管理微前端的獨立發(fā)布、上下線和組合測試等等問題的。這樣順便也給了我們一個條件,可以給 sourceMap 管理起來。

          結(jié)語

          上面就是本次分享的全部,分享了關(guān)于微前端沙盒字節(jié)跳動兩年來使用和實現(xiàn)的經(jīng)驗,以及面對這些挑戰(zhàn)時的思考過程。非常幸運我們的項目有足夠多給力的伙伴們支持,最終獲得了比較大的成功,也非常明顯地提升了重量級的產(chǎn)品的質(zhì)量。

          微前端和很多前沿和剛剛發(fā)展的概念一樣,本身還在快速的演進和驗證的過程中,我們的具體實踐也一直在快速的變化,在不斷地發(fā)現(xiàn)弱點和糾正它們,也在努力發(fā)展更多的可能。在這個從種種不完美到更完美的奮斗過程中,能給讀者分享我們的成果是我們的一種榮幸。而且在分享后,如果能收到指教、討論和建議我們會更加感激,并且非常歡迎。也歡迎更多的有識之士加入我們,聯(lián)系請發(fā)往郵箱 aishiguang@bytedance.com 或關(guān)注 內(nèi)推鏈接。

          前端開發(fā)(Vue)

          一、微前端概述

          1. 什么是微前端?

            為了解決龐大的一整塊后端服務(wù)帶來的變更與擴展方面的限制,出現(xiàn)了微服務(wù)架構(gòu)。然而,越來越重的前端工程也面臨同樣的問題,自然地想到了將微服務(wù)思想應(yīng)用(照搬)到前端,于是有了“微前端(micro-frontends)”的概念。即,一種由獨立交付的多個前端應(yīng)用組成整體的架構(gòu)風(fēng)格。具體的,將前端應(yīng)用分解成一些更小、更簡單的能夠獨立開發(fā)、測試、部署的小塊,而在用戶看來仍然是內(nèi)聚的單個產(chǎn)品。

            我們常見后臺項目通常長這樣:

          1

            如果我們的項目需要開發(fā)某個新的功能,而這個功能另一個項目已經(jīng)開發(fā)好,我們想直接復(fù)用時。

            說明:我們需要的只是別人項目的這個功能頁面的內(nèi)容部分,不需要別人項目的頂部導(dǎo)航和菜單。

          一個比較笨的辦法就是直接把別人項目這個頁面的代碼拷貝過來,但是萬一別人不是 vue 開發(fā)的,或者說vue 版本、UI 庫等不同,以及別人的頁面加載之前操作(路由攔截,鑒權(quán)等)我們都需要拷貝過來,更重要的問題是,別人代碼有更新,我們?nèi)绾巫龅酵礁隆I踔廉?dāng)別的項目采用其它技術(shù)棧時,如何集成?顯然復(fù)制代碼是行不通的。

            以前端組件的概念作類比,我們可以把每個被拆分出的子應(yīng)用看作是一個應(yīng)用級組件,每個應(yīng)用級組件專門實現(xiàn)某個特定的業(yè)務(wù)功能(如商品管理、訂單管理等)。這里實際上談到了微前端拆分的原則:即以業(yè)務(wù)功能為基本單元。經(jīng)過拆分后,整個系統(tǒng)的結(jié)構(gòu)也發(fā)生了變化:

            如上圖所示,左側(cè)是傳統(tǒng)大型單頁應(yīng)用的前端架構(gòu),所有模塊都在一個應(yīng)用內(nèi),由應(yīng)用本身負責(zé)路由管理,是應(yīng)用分發(fā)路由的方式;而右側(cè)是基座模式下的系統(tǒng)架構(gòu),各個子應(yīng)用互不相關(guān),單獨運行在不同的服務(wù)上,由基座應(yīng)用根據(jù)路由選擇加載哪個應(yīng)用到頁面內(nèi),是路由分發(fā)應(yīng)用的方式。這種方式使得各個模塊的耦合性大大降低,而微前端需要解決的主要問題就是如何拆分和組織這些子應(yīng)用。

          典型的基于vue-router的Vue應(yīng)用與這種架構(gòu)存在著很大的相似性:

          2. 巨無霸項目的存在的問題

          • 代碼越來越多,打包越來越慢,部署升級麻煩,一些插件的升級和公共組件的修改需要考慮的更多,很容易牽一發(fā)而動全身。
          • 項目太大,參與人員越多,代碼規(guī)范比較難管理,代碼沖突也頻繁。
          • 產(chǎn)品功能齊全,但是客戶往往只需要其中的部分功能。剝離不需要的代碼后,需要獨立制定版本,獨立維護,增加人力成本。

            微前端的誕生也是為了解決以上問題:

          •   復(fù)用(嵌入)別人的項目頁面,但是別人的項目運行在他自己的環(huán)境之上。
          •   巨無霸應(yīng)用拆分成一個個的小項目,這些小項目獨立開發(fā)部署,又可以自由組合進行售賣。

            使用微前端的好處:

          •   技術(shù)棧無關(guān),各個子項目可以自由選擇框架,可以自己制定開發(fā)規(guī)范。
          •   快速打包,獨立部署,互不影響,升級簡單。
          •   可以很方便的復(fù)用已有的功能模塊,避免重復(fù)開發(fā)。

          二、常見微前端方案

            目前主流的微前端方案包括以下幾個:

          • iframe
          • 基座模式,主要基于路由分發(fā),qiankun和single-spa就是基于這種模式
          • 組合式集成,即單獨構(gòu)建組件,按需加載,類似npm包的形式
          • EMP,主要基于Webpack5 Module Federation
          • Web Components

            iframe:是傳統(tǒng)的微前端解決方案,基于iframe標簽實現(xiàn),技術(shù)難度低,隔離性和兼容性很好,但是性能和使用體驗比較差,多用于集成第三方系統(tǒng);

            基座模式:主要基于路由分發(fā),即由一個基座應(yīng)用來監(jiān)聽路由,并按照路由規(guī)則來加載不同的應(yīng)用,以實現(xiàn)應(yīng)用間解耦;

            組合式集成:把組件單獨打包和發(fā)布,然后在構(gòu)建或運行時組合。

            EMP:基于Webpack5 Module Federation,一種去中心化的微前端實現(xiàn)方案,它不僅能很好地隔離應(yīng)用,還可以輕松實現(xiàn)應(yīng)用間的資源共享和通信。

            Web Components:是官方提出的組件化方案,它通過對組件進行更高程度的封裝,來實現(xiàn)微前端,但是目前兼容性不夠好,尚未普及。

            總的來說,iframe主要用于簡單并且性能要求不高的第三方系統(tǒng);組合式集成目前主要用于前端組件化,而不是微前端;基座模式、EMP和Web Components是目前主流的微前端方案。

            目前微前端最常用的有兩種解決方案:iframe 方案和 基座模式方案。

          1. iframe方案

            iframe 大家都很熟悉,使用簡單方便,提供天然的 js/css 隔離,也帶來了數(shù)據(jù)傳輸?shù)牟槐悖恍?shù)據(jù)無法共享(主要是本地存儲、全局變量和公共插件),兩個項目不同源(跨域)情況下數(shù)據(jù)傳輸需要依賴postMessage 。

            iframe 有很多坑,但是大多都有解決的辦法:

            1. 頁面加載問題

            iframe 和主頁面共享連接池,而瀏覽器對相同域的連接有限制,所以會影響頁面的并行加載,阻塞onload 事件。每次點擊都需要重新加載,雖然可以采用 display:none 來做緩存,但是頁面緩存過多會導(dǎo)致電腦卡頓。(無法解決)

            2. 布局問題

            iframe 必須給一個指定的高度,否則會塌陷。

            解決辦法:子項目實時計算高度并通過postMessage 發(fā)送給主頁面,主頁面動態(tài)設(shè)置 iframe高度。有些情況會出現(xiàn)多個滾動條,用戶體驗不佳。

            3. 彈窗及遮罩層的問題

            彈窗只能在 iframe 范圍內(nèi)垂直水平居中,沒法在整個頁面垂直水平居中。

            解決辦法1:通過與框架頁面消息同步解決,將彈窗消息發(fā)送給主頁面,主頁面來彈窗,對原項目改動大且影響原項目的使用。

            解決辦法2:修改彈窗的樣式:隱藏遮罩層,修改彈窗的位置。

            4. iframe 內(nèi)的 div 無法全屏

            彈窗的全屏,指的是在瀏覽器可視區(qū)全屏。這個全屏指的是占滿用戶的屏幕。

            全屏方案,原生方法使用的是Element.requestFullscreen(),插件:vue-fullscreen。當(dāng)頁面在 iframe 里面時,全屏?xí)箦e,且dom 結(jié)構(gòu)錯亂。

            解決方案:iframe 標簽設(shè)置 allow="fullscreen" 屬性即可

            5. 瀏覽器前進/后退問題

            iframe 和主頁面共用一個瀏覽歷史,iframe 會影響頁面的前進后退。大部分時候正常,iframe 多次重定向則會導(dǎo)致瀏覽器的前進后退功能無法正常使用。并且 iframe 頁面刷新會重置(比如說從列表頁跳轉(zhuǎn)到詳情頁,然后刷新,會返回到列表頁),因為瀏覽器的地址欄沒有變化,iframe 的 src 也沒有變化。

            6. iframe 加載失敗的情況不好處理

            非同源的 iframe 在火狐及 chorme 都不支持onerror 事件。

            解決辦法1:onload 事件里面判斷頁面的標題,是否 404 或者 500

            解決辦法2:使用 try catch 解決此問題,嘗試獲取 contentDocument 時將拋出異常。

          2. 基座模式方案

            基座模式方案以single-spa和qiankun為代表,這里我選擇qiankun。

            qiankun 是螞蟻金服開源的一款框架,它是基于single-spa 的。他在 single-spa 的基礎(chǔ)上,實現(xiàn)了開箱即用,除一些必要的修改外,子項目只需要做很少的改動,就能很容易的接入。

            qiankun框架官網(wǎng):https://qiankun.umijs.org/zh/。

            微前端中子項目的入口文件常見的有兩種方式:JS entry 和 HTML entry。純 single-spa 采用的是 JS entry,而 qiankun 既支持 JS entry,又支持 HTML entry。

            JS entry 的要求比較苛刻:

            (1)將 css 打包到 js 里面

            (2)去掉 chunk-vendors.js,

            (3)去掉文件名的 hash 值

            (4)將 single-spa 模式的入口文件( app.js )放置到 index.html 目錄,其他文件不變,原因是要截取app.js 的路徑作為 publicPath。

            建議使用 HTML entry ,使用起來和 iframe 一樣簡單,但是用戶體驗比 iframe 強很多。qiankun 請求到子項目的 index.html 之后,會先用正則匹配到其中的 js/css 相關(guān)標簽,然后替換掉,它需要自己加載 js并運行,然后去掉 html/head/body 等標簽,剩下的內(nèi)容原樣插入到子項目的容器中 。

          二、微前端方案實踐

            以“大數(shù)據(jù)分析”項目為例,將客戶特有的需求,如“電子路單”、“數(shù)據(jù)填報”單獨提取為可獨立運行的子項目。

            大數(shù)據(jù)分析項目改造為主應(yīng)用基座,代碼倉庫地址:http://192.168.1.102/zouqiongjun/big-data-web.git。

            客戶自定義需求單獨作為子應(yīng)用項目,代碼倉庫地址:http://192.168.1.102/zouqiongjun/zibo-custom-web.git。

          1. 各應(yīng)用工程代碼結(jié)構(gòu)

            sass-base-web:主倉庫,主要存放一些批量操作的腳本,用于聚合管理倉庫和一鍵編譯、一鍵部署。

            倉庫代碼結(jié)構(gòu)如下圖所示:

            big-data-web:大數(shù)據(jù)分析主應(yīng)用

            zibo-custom-web:客戶自定義需求,微應(yīng)用倉庫

            子應(yīng)用可以獨立運行,但是當(dāng)前子應(yīng)用是直接嵌套在主應(yīng)用的main內(nèi)容區(qū)域,所以暫時并沒有單獨提供左側(cè)菜單導(dǎo)航,后續(xù)如有需要可以擴展和補充此功能。

          2. 主應(yīng)用big-data-web改造

            將普通的項目改造成 qiankun 主應(yīng)用基座,需要進行三步操作:

            (1) 創(chuàng)建微應(yīng)用容器 - 用于承載微應(yīng)用,渲染顯示微應(yīng)用;

            (2) 注冊微應(yīng)用 - 設(shè)置微應(yīng)用激活條件,微應(yīng)用地址等等;

            (3) 啟動 qiankun;

            注意:由于big-data-web主應(yīng)用的路由采用的是hash模式,所以子應(yīng)用的路由也應(yīng)該采用hash模式。

          1.1 安裝 qiankun

          $ yarn add qiankun # 或者 npm i qiankun -S

          1.2. 在主應(yīng)用中注冊微應(yīng)用

            為了使用keepAlive緩存,這里我們采用手動加載微應(yīng)用的方式。

            當(dāng)微應(yīng)用信息注冊完之后,一旦瀏覽器的 url 發(fā)生變化,便會自動觸發(fā) qiankun 的匹配邏輯,所有activeRule 規(guī)則匹配上的微應(yīng)用就會被插入到指定的container 中,同時依次調(diào)用微應(yīng)用暴露出的生命周期鉤子。

            在views目錄下,新建AppVueHash.vue,作為子應(yīng)用的容器,代碼如下:

          <template>
          <div class="zibo-custom-web">
               <div id="zibo-custom-web" class="app-view-box"></div>
          </div>
          </template>
          <script>
          export default {};
          </script>
          <style lang="scss" scoped>
          .zibo-custom-web{
            position: relative;
          }
          </style>

            這個id屬性要唯一,最終子應(yīng)用的內(nèi)容將會掛載在這里。

            ContainerOther.vue代碼改造:

            <!-- 主體視圖層 -->
                  <div class="avue-view-contain" v-show="!isSearch">
                    <keep-alive>
                      <router-view
                        class="avue-view keep-alive"
                        v-if="$route.meta.keepAlive && isActiveRoute"
                        v-show="!showAppVueHash"
                      />
                    </keep-alive>
                    <router-view
                      class="avue-view"
                      v-if="!$route.meta.keepAlive && isActiveRoute"
                      v-show="!showAppVueHash"
                    />
                    <AppVueHash v-show="showAppVueHash" />
                  </div>

          js代碼:

          import router from "@/router/router";
          import store from "@/store";
          import AppVueHash from "@/views/AppVueHash.vue";
          import { loadMicroApp } from "qiankun";
          //子項目路由前綴
          const isChildRoute = path => website.childRoute.some(item => path.startsWith(item));
          const apps = [
            {
              name: "/zibo-custom-web",
              entry: window.configs.VUE_APP_ZIBO_CUSTOM_URL,
              container: "#zibo-custom-web",
              props: { data: { store, router } },
              sandbox: {
                strictStyleIsolation: true // 開啟樣式隔離
              }
            }
          ];
          //控制微應(yīng)用手動加載
              ctrlMicroApp(path){
                 if (isChildRoute(path)) {
                  this.showAppVueHash = true;
                  this.$nextTick(() => {
                    //手動加載
                    if(!this.mounted){
                      this.loadApps = apps.map(item => loadMicroApp(item))
                      this.mounted=true;
                    }  
                  });
                } else {
                  this.showAppVueHash = false;
                }

            這里的container屬性值,必須和AppVueHash.vue組件中的id值保持一致。

            根據(jù)url地址判斷是否是子應(yīng)用,如果是子應(yīng)用,則手動加載,否則隱藏子應(yīng)用容器,只加載主應(yīng)用的router-view。

            在ContainerOther第一次加載或路由變化時手動加載微應(yīng)用:

          mounted() {
              this.init();
              setTheme(this.themeName);
              this.ctrlMicroApp(this.$route.path)
            },
            watch: {
              $route(val) {
                this.ctrlMicroApp(val.path);
          },
              tagList(newVal,oldVal){
                let starts='';
                const childRoute = website.childRoute;
                childRoute.forEach((n,i)=>{
                  if(i<childRoute.length-1){
                    starts+=`^${n}|`;
                  }else{
                    starts+=`^${n}`;
                  }
                })
                const patt = new RegExp(`${starts}`);
                //之前存在子應(yīng)用頁簽
                const before = oldVal.some(item=>{
                  return patt.test(item.value);
                });
                //現(xiàn)在存在子應(yīng)用頁簽
                const now = newVal.some(item=>{
                  return patt.test(item.value);
                });
                if(before && !now){
                  this.mounted=false;
                  this.loadApps.forEach(app=>{
                    app.unmount();  
                  })
                }
              } 

            監(jiān)聽tab頁簽變化,關(guān)閉頁簽時,需要卸載子應(yīng)用。

          3. qiankun 子項目zibo-custom-web

          1. 在 src 目錄新增文件 public-path.js:
          if (window.__POWERED_BY_QIANKUN__) {
              // eslint-disable-next-line no-undef
              __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
            }
          1. 修改 index.html 中項目初始化的容器,不要使用 #app ,避免與其他的項目沖突,建議小駝峰寫法
              <div id="appVueHash"></div>
          1. 修改入口文件 main.js:
          // -----------子應(yīng)用微前端start-------------------
          let router = null;
          let instance = null;
          
          function render({ data = {} , container } = {}) {
            router = new VueRouter({
              routes,
            });
            instance = new Vue({
              router,
              store,
              data(){
                return {
                  parentRouter: data.router,
                  parentVuex: data.store,
                }
              },
              render: h => h(App),
            }).$mount(container ? container.querySelector('#appVueHash') : '#appVueHash');
          }
          if (!window.__POWERED_BY_QIANKUN__) {
            render();
          }
          //測試全局變量污染
          console.log('window.a',window.a)
          export async function bootstrap() {
            console.log('vue app bootstraped');
          }
          export async function mount(props) {
            console.log('props from main framework', props.data);
            render(props);
          }
          export async function unmount() {
            instance.$destroy();
            instance.$el.innerHTML = "";
            instance = null;
            router = null;
          }
          // -----------子應(yīng)用微前端end-------------------

            主要改動是:引入修改 publicPath 的文件和export 三個生命周期。

            注意:

          • webpack 的 publicPath 值只能在入口文件修改,之所以單獨寫到一個文件并在入口文件最開始引入,是因為這樣做可以讓下面所有的代碼都能使用這個。
          • 路由文件需要 export 路由數(shù)據(jù),而不是實例化的路由對象,路由的鉤子函數(shù)也需要移到入口文件。
          • 在 mount 生命周期,可以拿到父項目傳遞過來的數(shù)據(jù),router 用于跳轉(zhuǎn)到主項目/其他子項目的路由,store 是父項目的實例化的 Vuex(也可以傳遞其他數(shù)據(jù)過來)。
          1. 修改打包配置 vue.config.js:
          const { name } = require("./package");
          module.exports = {
            outputDir: "../sass-base-web/cicd-config/test/zibo-custom-web",
            devServer: {
              port: 9010,
              // 關(guān)閉主機檢查,使微應(yīng)用可以被 fetch
              disableHostCheck: true,
              // 配置跨域請求頭,解決開發(fā)環(huán)境的跨域問題
              headers: {
                "Access-Control-Allow-Origin": "*",
              },
              proxy: {
                "/api": {
                  //本地服務(wù)接口地址
                  target: "http://192.168.10.112:10067", //cas
                  ws: true,
                  pathRewrite: {
                    "^/api": "/",
                  },
                },
              },
            },
             // 以下配置可以修復(fù)一些字體文件加載路徑問題
            chainWebpack: (config) => {
              //忽略的打包文件
              config.externals({
                vue: "Vue",
                "vue-router": "VueRouter",
                vuex: "Vuex",
                axios: "axios",
                "element-ui": "ELEMENT",
              });
              config
                .plugin('html')
                .tap(args => {
                  args[0].name = name;
                  return args
                });
              config.module
                .rule("fonts")
                .test(/.(ttf|otf|eot|woff|woff2)$/)
                .use("url-loader")
                .loader("url-loader")
                .tap((options) => ({ name: "/fonts/[name].[hash:8].[ext]" }))
                .end();
            },
            // 自定義webpack配置
            configureWebpack: {
              output: {
                library: `${name}-[name]`, // 微應(yīng)用的包名,這里與主應(yīng)用中注冊的微應(yīng)用名稱一致
                libraryTarget: "umd", // 把子應(yīng)用打包成 umd 庫格式
                jsonpFunction: `webpackJsonp_${name}`, //webpack打包之后保存在window中的key,各個子應(yīng)用不一致
              },
            },
          };

            這里主要就兩個配置,一個是允許跨域,另一個是打包成 umd 格式。為什么要打包成 umd 格式呢?是為了讓 qiankun 拿到其 export 的生命周期函數(shù)。

            注意: 這個 name 默認從 package.json 獲取,可以自定義,只要和父項目注冊時的 name 保持一致即可。

            vue.config.js中

            outputDir: "../sass-base-web/cicd-config/test/zibo-custom-web",

            這里我子應(yīng)用項目編譯后會將打包文件打包到sass-base-web項目中的zibo-custom-web下。

          1. 路由動態(tài)加載

            需要給子項目所有的路由都添加一個前綴,子項目的路由跳轉(zhuǎn)如果之前使用的是 path 也需要修改,用name 跳轉(zhuǎn)則不用。

            avue-router.js:

           const oRouter = {
                    path: "/zibo-custom-web",
                    name: "RouterView",
                    component(resolve) {
                      require(["@/components/RouterView.vue"], resolve);
                    },
          
                    children: [
                      {
                        path: path,
                        component(resolve) {
                          require([`../${component}.vue`], resolve);
                        },
                        name: name,
                        meta: meta,
                      },
                    ],
                  };
                  aRouter.push(oRouter);

          4. 狀態(tài)管理,主應(yīng)用和微應(yīng)用之間的通信

            qiankun 通過 initGlobalState: 定義全局狀態(tài),并返回通信方法,建議在主應(yīng)用使用,微應(yīng)用通過props 獲取通信方法;

            onGlobalStateChange: 在當(dāng)前應(yīng)用監(jiān)聽全局狀態(tài),有變更觸發(fā) callback;

            setGlobalState: 按一級屬性設(shè)置全局狀態(tài),微應(yīng)用中只能修改已存在的一級屬性; 換句話說只能修改主用于預(yù)先定義的屬性,后面添加的屬性無效。

            官方例子:發(fā)布-訂閱的設(shè)計模式:

            主應(yīng)用:

          import { initGlobalState, MicroAppStateActions } from 'qiankun';
          // 初始化 state
          const actions: MicroAppStateActions = initGlobalState(state);
          
          actions.onGlobalStateChange((state, prev) => {
            // state: 變更后的狀態(tài); prev 變更前的狀態(tài)
            console.log(state, prev);
          });
          actions.setGlobalState(state);
          actions.offGlobalStateChange();

            子應(yīng)用:

          // 從生命周期 mount 中獲取通信方法,使用方式和 master 一致
          export function mount(props) {
              props.onGlobalStateChange((state, prev) => {
                // state: 變更后的狀態(tài); prev 變更前的狀態(tài)
                console.log(state, prev);
              });
              props.setGlobalState(state);
            }

            如果主應(yīng)用和子應(yīng)用都是vue技術(shù)棧,可以在子應(yīng)用中把數(shù)據(jù)傳遞給子應(yīng)用,例如store。

          props: { data: { store, router } },

          5. 各應(yīng)用之間的獨立倉庫以及聚合管理

            實際開發(fā)中項目存儲在公司倉庫中,以 gitLab 為例, 當(dāng)子應(yīng)用一多,全部放在一個倉庫下面, 這時候就顯得很臃腫了,也很龐大,大大的增加了維護成本,和開發(fā)效率;

          我們可以通過 sh 腳本, 初始只需要克隆主倉庫代碼, 然后通過 sh 腳本去一鍵拉取所有子應(yīng)用代碼。

            這里我將單獨創(chuàng)建一個用來編譯和打包的主倉庫項目sass-base-web,倉庫地址:http://192.168.1.102/zouqiongjun/sass-base-web.git。

            項目根目錄下,新建 script/clone-all.sh 文件,內(nèi)容如下:

          # 子服務(wù) gitLab 地址
          SUB_SERVICE_GIT=('http://192.168.1.102/zouqiongjun/big-data-web.git' 'http://192.168.1.102/zouqiongjun/zibo-custom-web.git')
          SUB_SERVICE_NAME=('big-data-web' 'zibo-custom-web')
          
          # 子服務(wù)
          if [ ! -d "sub-service" ]; then
            echo '創(chuàng)建sub-service目錄...'
            mkdir sub-service
          fi
          echo '進入sub-service目錄...'
          cd sub-service
          
          # 遍歷克隆微服務(wù)
          for i in ${!SUB_SERVICE_NAME[@]}
          do
            if [ ! -d ${SUB_SERVICE_NAME[$i]} ]; then
              echo '克隆微服務(wù)項目'${SUB_SERVICE_NAME[$i]}
              git clone ${SUB_SERVICE_GIT[$i]}
            fi
          done
           
          echo '腳本結(jié)束...'
          # 克隆完成

            當(dāng)我們啟動主項目的時候,如果想要使用所有子應(yīng)用的功能,子應(yīng)用,需要一個一個啟動,這樣無論是開發(fā)還是編譯都十分不便。

            考慮到國內(nèi)使用npm裝包可能會由于網(wǎng)絡(luò)的原因安裝失敗,可以讓npm使用國內(nèi)淘寶鏡像。

            執(zhí)行命令:npm config set registry https://registry.npm.taobao.org。

            在這個主倉庫項目里面,我們只需要安裝一個npm-run-all插件。

            運行:yarn add npm-run-all -D或者npm i -D。

            該項目下只有一個package.json文件,用于配置編譯和打包命令,代碼如下:

          {
            "name": "sass-big-data-web",
            "version": "1.0.0",
            "description": "`qiankun`來實現(xiàn)`vue`技術(shù)棧的前端微服務(wù)",
            "main": "index.js",
            "scripts": {
              "clone:all": "bash ./scripts/clone-all.sh",
              "install:zibo": "cd ./sub-service/zibo-custom-web && npm install",
              "install:main": "cd ./sub-service/big-data-web && npm install",
              "install-all": "npm-run-all install:*",
              "start:zibo": "cd ./sub-service/zibo-custom-web && npm run serve ",",
              "start:main": "cd ./sub-service/big-data-web && npm run serve",
              "start-all": "npm-run-all --parallel start:*",
              "serve-all": "npm-run-all --parallel start:*",
              "build:zibo": "cd ./sub-service/zibo-custom-web && npm run build",
              "build:main": "cd ./sub-service/big-data-web && npm run build",
              "build-all": "npm-run-all --parallel build:*"
            },
            "repository": {
              "type": "git",
              "url": "http://192.168.1.102/zouqiongjun/sass-big-data-web.git"
            },
            "keywords": [],
            "author": "",
            "license": "ISC",
            "devDependencies": {
              "npm-run-all": "^4.1.5"
            }
          }

            要執(zhí)行yarn clone:all,需要用到bash,跳轉(zhuǎn)到sass-base-web目錄,右鍵鼠標打開Git bash窗口,如下圖所示:

            這樣當(dāng)我們把各個代碼倉庫的代碼都拉取到sub-service這個目錄下面來,如下圖所示:

            代碼拉取完成后, 緊接著就是下載各個項目的依賴及運行。

            運行npm run serve-all則可以自動執(zhí)行package.json中配置的命令,這個命令最終會執(zhí)行以下三個執(zhí)行命令:

              "start:zibo": "cd ../zibo-custom-web && npm run serve ",
              "start:main": "cd ../big-data-web && npm run serve",

            這樣就不需要我們自己一個一個單獨的去運行各個項目了。

            總體運行步驟: 第一步 clone 主應(yīng)用, 然后依次執(zhí)行 yarn clone:all --> yarn install-all --> yarn start-all 即可運行整個項目。

            build-all:可以編譯整個項目。

            sub-service目錄,將其添加到.gitignore當(dāng)中,因為在sass-base-web項目當(dāng)中,我們只需要配置和編譯及打包用,并不需要真正的將所有子應(yīng)用的代碼都提交到sass-base-web項目中,各子應(yīng)用都有自己私有的倉庫。

          6. 子項目開發(fā)的一些注意事項

            (1)所有的資源(圖片/音視頻等)都應(yīng)該放到src 目錄,不要放在 public 或者static。資源放 src 目錄,會經(jīng)過 webpack 處理,能統(tǒng)一注入 publicPath。否則在主項目中會404。

            (2)避免 css 污染。組件內(nèi)樣式的 css-scoped是必須的。

            (3)給 body 、 document 等綁定的事件,請在unmount 周期清除

            (4)謹慎使用 position:fixed

            在父項目中,這個定位未必準確,應(yīng)盡量避免使用,確有相對于瀏覽器窗口定位需求,可以用position: sticky,但是會有兼容性問題(IE不支持)。

            常見問題見官網(wǎng):https://qiankun.umijs.org/zh/faq

          7. 部署

          1. 常規(guī)部署

            主應(yīng)用和微應(yīng)用都是獨立開發(fā)和部署,即它們都屬于不同的倉庫和服務(wù)。

            場景:主應(yīng)用和微應(yīng)用部署到同一個服務(wù)器(同一個IP和端口)

            如果服務(wù)器數(shù)量有限,或不能跨域等原因需要把主應(yīng)用和微應(yīng)用部署到一起。通常的做法是主應(yīng)用部署在一級目錄,微應(yīng)用部署在二/三級目錄。

            若微應(yīng)用想部署在非根目錄,在微應(yīng)用打包之前需要做兩件事:

          • 必須配置 webpack 構(gòu)建時的 publicPath 為目錄名稱,更多信息請看 webpack 官方說明 和vue-cli3 的官方說明。
          • history 路由的微應(yīng)用需要設(shè)置 base ,值為目錄名稱,用于獨立訪問時使用。

            部署之后注意三點:

          • activeRule 不能和微應(yīng)用的真實訪問路徑一樣,否則在主應(yīng)用頁面刷新會直接變成微應(yīng)用頁面。
          • 微應(yīng)用的真實訪問路徑就是微應(yīng)用的 entry,entry 可以為相對路徑。
          • 微應(yīng)用的 entry 路徑最后面的 / 不可省略,否則 publicPath 會設(shè)置錯誤,例如子項的訪問路徑是 http://localhost:8080/app1,那么 entry 就是 http://localhost:8080/app1/。

            通過配置 nginx 端口到目錄的轉(zhuǎn)發(fā)。須要對外開放子利用對應(yīng)的端口,將編譯好的利用文件放到對應(yīng)的配置目錄。

            跳轉(zhuǎn)到sass-base-web目錄,執(zhí)行npm run build-all,會自動執(zhí)行所有build:開頭的命令:

              "build:zibo": "cd ../zibo-custom-web && npm run build",
              "build:control": "cd ../control-center && npm run build",
              "build:main": "cd ../big-data-web && npm run build",
              "build-all": "npm-run-all --parallel build:*"

            zibo-custom-web目錄結(jié)構(gòu)如下圖所示:

            這里是子應(yīng)用和主應(yīng)用部署在同一臺服務(wù)器上,且IP和端口相同,nginx不需要額外設(shè)置。

            如果子應(yīng)用和主應(yīng)用部署在同一臺服務(wù)器上, 但是端口不同,需要修改vue.config.js中的outputDir,這個是打包編譯后代碼存放的路徑,這個不做配置,默認會將代碼編譯打包到當(dāng)前根目錄下,并生成一個dist目錄用于存放編譯后的代碼,如下圖所示:

          修改nginx.conf配置:

           #gzip  on;
                upstream gateway { server 192.168.31.136:32067;}
               # 主應(yīng)用
                  server {
                  listen   32043;
                  server_name  web;
                  root  /dist;
                  # 關(guān)閉端口重定向
                  # port_in_redirect off;
                  #charset koi8-r;
                  access_log /var/log/nginx/nginx.log;
          
                  location / {
                  proxy_set_header Host $http_host;
                  proxy_set_header X-Real-IP $remote_addr;
                  proxy_set_header REMOTE-HOST $remote_addr;
                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                  }
          
                  location ^~/api/ {  
                      proxy_read_timeout 600s;
                      proxy_set_header Host $host; 
                      proxy_set_header X-Real-IP $remote_addr; 
                      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                      proxy_buffering off; 
                      rewrite ^/api/(.*)$ /$1 break; 
                      proxy_pass http://gateway; 
                      }
                  }
          
             # 子應(yīng)用
              server {
                  listen   9010;
                  server_name  cus_web;
                  # 子應(yīng)用編譯后的代碼路徑
                  root  /zibo-custom-web;  
                  # 允許跨域
                  add_header Access-Control-Allow-Origin *;
                  # 關(guān)閉端口重定向
                  # port_in_redirect off;
                  # charset koi8-r;
                  access_log /var/log/nginx/nginx.log;
                  location ^~/zibo-custom-web/ {
                  proxy_set_header Host $http_host;
                  proxy_set_header X-Real-IP $remote_addr;
                  proxy_set_header REMOTE-HOST $remote_addr;
                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                  }
          
                  location ^~/api/ {  
                      proxy_read_timeout 600s;
                      proxy_set_header Host $host; 
                      proxy_set_header X-Real-IP $remote_addr; 
                      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                      proxy_buffering off; 
                      rewrite ^/api/(.*)$ /$1 break; 
                      proxy_pass http://gateway; 
                      }
              }

          2. docker nginx 配置

            此處 nginx 主要作用是用于端口目錄轉(zhuǎn)發(fā),并配置主應(yīng)用訪問子應(yīng)用的跨域問題。

            使用 docker 配置部署 nginx:

          # docker-compose.yml
          version: '3.1'
          services:
            nginx:
              restart: always
              image: nginx
              container_name: nginx
              ports:
                - 8888:80
                - 8889:8889
                - 7100:7100
                - 7101:7101
              volumes:
                - /app/volumes/nginx/nginx.conf:/etc/nginx/nginx.conf
                - /app/volumes/nginx/html:/usr/share/nginx/html
                - /app/micro/portal:/app/micro/portal
                - /app/micro/app1:/app/micro/app1
                - /app/micro/app2:/app/micro/app2

            將編譯后的主應(yīng)用以及子應(yīng)用放到對應(yīng)的數(shù)據(jù)卷掛載目錄即可,如主應(yīng)用 /app/micro/portal。  同理,也需要將配置好的 nginx.conf 文件放到指定的數(shù)據(jù)卷掛載目錄,使用 docker-compose up -d 啟動即可。

            nginx 端口目錄轉(zhuǎn)發(fā)配置:

          # nginx.conf
          user  nginx;
          worker_processes  1;
          error_log  /var/log/nginx/error.log warn;
          pid        /var/run/nginx.pid;
          
          events {
              worker_connections  1024;}
          http {
              include       /etc/nginx/mime.types;
              default_type  application/octet-stream;
              log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                                '$status $body_bytes_sent "$http_referer" '
                                '"$http_user_agent" "$http_x_forwarded_for"';
          
              access_log  /var/log/nginx/access.log  main;
          
              sendfile        on;
              #tcp_nopush     on;
              keepalive_timeout  65;
          
              #gzip  on;
              include /etc/nginx/conf.d/*.conf;
              server {
                listen    8889;
                server_name 192.168.2.192;
                location / {
                  root /app/micro/portal;
                  index index.html;
                  try_files $uri $uri/ /index.html;
                }
              }
              server {
                listen    7100;
                server_name 192.168.2.192;
          
                # 配置跨域訪問,此處是通配符,嚴格生產(chǎn)環(huán)境的話可以指定為主應(yīng)用 192.168.2.192:8889
                add_header Access-Control-Allow-Origin *;
                add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
                add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
                location / {
                  root /app/micro/app1;
                  index index.html;    
                  try_files $uri $uri/ /index.html;
                }
              }
              server {
                listen    7101;
                server_name 192.168.2.192;
               
                # 配置跨域訪問,此處是通配符,嚴格生產(chǎn)環(huán)境的話可以指定為主應(yīng)用 192.168.2.192:8889
                add_header Access-Control-Allow-Origin *;
                add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
                add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
                
                location / {
                  root /app/micro/app2;
                  index index.html;   
                  try_files $uri $uri/ /index.html;
                }
              }}

            部署到生產(chǎn),需要修改big-data-web/public/util/config.js中的VUE_APP_ZIBO_CUSTOM_URL配置項:

          (function() {
            window.configs = {
              VUE_APP_CASLOGINURL: "http://192.168.1.99:32080/cas", //cas登錄地址
              VUE_APP_REDIRECTURL: "http://192.168.51.61:8888/big-data/", //前端部署地址
              VUE_APP_SOCKET: "ws://192.168.31.136:32061", //websocket地址'
              VUE_APP_AMAPURLPREFIX: "https://webapi.amap.com", //高德地圖地址
              VUE_APP_ZIBO_CUSTOM_URL:"http://localhost:9010",//自定義微應(yīng)用地址
              //================================================
          
              VUE_APP_AMAPKEY: "xxxxxx" //高德key
            };
          })();
           

            這里config.js是為了配置文件外置,不需要編譯。

          8. 總結(jié)

            盡管qiankun框架支持各個子應(yīng)用使用不同的技術(shù)框架,但是都需要子應(yīng)用做相應(yīng)的改造,而且在其它技術(shù)棧中總是會時不時的出現(xiàn)各種難以預(yù)料的錯誤,一旦出現(xiàn)問題,都需要我們?nèi)ジ脑齑a。所以如果都是vue技術(shù)棧,建議使用qiankun做微前端。

            如果是第三方公司的項目接入進來,由于他們的代碼不受我們控制,需要酌情考慮是否用iframe。

            參考文獻:qiankun 微前端方案實踐及總結(jié)

          生志愿是考生本人升學(xué)意愿的真實表達,是投檔及錄取的重要依據(jù)。志愿一定要由考生本人填報,考生須對其所填報的志愿內(nèi)容和填報操作負全責(zé)。

          為了幫助考生填報志愿,我們編寫“2021年河北省普通高考志愿填報須知”,供考生參考。

          一、志愿填報的流程及注意事項

          (一)志愿填報時間是如何安排的?

          志愿填報期間,每日0時至6時為系統(tǒng)維護時間,不能填報志愿。

          (二)志愿填報的流程是什么?

          考生志愿填報采取遠程網(wǎng)上填報方式進行。

          考生須使用IE11、Chrome、Edge瀏覽器,其他類型及版本不予支持,由于瀏覽器類型及版本使用不當(dāng)造成的一切后果由考生自負。在規(guī)定時間內(nèi),考生可通過河北省教育考試院官方網(wǎng)站(http://www.hebeea.edu.cn),點擊相應(yīng)鏈接進入普通高校招生志愿填報系統(tǒng),也可以訪問https://gk.hebeea.edu.cn,通過河北省普通高校招生考試信息管理與服務(wù)平臺進入系統(tǒng),進行志愿填報。系統(tǒng)暫不支持使用手機、平板電腦等移動終端填報志愿。

          具體填報流程如下圖所示:

          1.考生須使用用戶名和密碼登錄系統(tǒng),用戶名為考生本人的考生號或身份證號,密碼為高考報名時考生本人所設(shè)置的密碼。

          2.首次登錄時,考生須認真閱讀《河北省2021年高考志愿填報承諾書》,并確認承諾。

          3.考生在志愿填報規(guī)定時間內(nèi),點擊“填報”按鈕,進入“2021年河北省普通高校招生志愿填報表”頁面。

          4.點擊所要填報的批次(段),進入該批次(段)志愿填報頁面。依次選擇計劃性質(zhì)、科類(填報高校專項計劃、高水平運動隊、高水平藝術(shù)團的考生還須選擇獲得的資格類型),然后輸入院校代號、專業(yè)代號(順序志愿還需選擇是否“服從專業(yè)調(diào)劑”),填報完成后須點擊“保存”按鈕進行志愿保存。保存時需要輸入系統(tǒng)登錄密碼。保存成功后系統(tǒng)會給出“XXXX批次志愿保存成功!”提示。點擊“返回填報表”按鈕可返回到“2021年河北省普通高校招生志愿填報表”頁面,所報志愿會在“所填志愿”欄中顯示出來。

          在填報平行志愿(不含對口)時,需要提醒的是:

          ①志愿填報系統(tǒng)提供了多種調(diào)整志愿順序的方法:清空、插入、上移、下移、刪除、調(diào)整、拖動。順序調(diào)整完成后,須點擊“保存”按鈕,否則調(diào)整志愿順序無效。

          ②志愿填報頁面左側(cè)的“志愿導(dǎo)航”欄可以拖動,方便考生快速定位及志愿保存。

          5.考生在填報過程中如需修改志愿信息,可在“批次入口選擇”欄中點擊相應(yīng)批次(段)名稱,進入志愿修改頁面,在規(guī)定時間內(nèi)進行志愿修改。在志愿填報截止時間前,考生可多次登錄系統(tǒng)進行志愿修改和保存,最終以其網(wǎng)上最后一次修改并保存成功的志愿為準。

          6.考生志愿核查無誤后,點擊“安全退出”按鈕安全退出系統(tǒng)。

          7.每個階段志愿填報結(jié)束后,系統(tǒng)將關(guān)閉3小時(以實際操作時間為準)進行系統(tǒng)維護。系統(tǒng)維護完成并重新開放后,考生可登錄志愿填報系統(tǒng),查看自己所填報的志愿信息。

          (三)志愿填報注意事項是什么?

          1.志愿填報系統(tǒng)是“一個批次(段)一保存”,而不是全部批次填報后統(tǒng)一保存,考生每批次(段)填報志愿后,必須點擊“保存”按鈕進行志愿保存,否則所填志愿無效。

          2.考生應(yīng)在規(guī)定時間內(nèi)填報志愿。未在規(guī)定時間內(nèi)完成網(wǎng)上填報志愿的考生視為自動放棄志愿填報。

          3.考生應(yīng)增強自身信息安全意識。志愿填報要由考生本人操作,不要讓他人代為操作。請考生不要將密碼設(shè)置得過于簡單,并妥善保管密碼,不要將密碼告訴他人,以防被他人篡改志愿,影響錄取。因考生本人泄漏密碼或由他人代為填報而造成的一切后果由考生承擔(dān)。

          4.考生要按照志愿順序填報平行志愿。在進行志愿保存時,所填志愿序號必須連續(xù),中間不能存在為空情況。例如填報本科批志愿時,始終未填序號1(第一行)的院校及專業(yè),而跳過去直接填了序號2(第二行)的院校及專業(yè),志愿填報系統(tǒng)不予支持。

          5.多名考生使用同一臺計算機填報志愿時,每位考生填報志愿后一定要點擊“安全退出”按鈕,并關(guān)閉所有顯示本人信息的頁面,否則,后一位考生所填報的志愿信息可能會覆蓋前面考生的志愿信息。同時還要注意,不要同時打開兩個或兩個以上填報頁面,以免發(fā)生錯誤。

          6.考生在上網(wǎng)填報之前應(yīng)先填好紙質(zhì)《2021年河北省普通高校招生考生志愿填報草表》(屆時可從省教育考試院官網(wǎng)下載打印),盡量不要在網(wǎng)上一邊思考一邊填報。這樣既可以提高網(wǎng)上填報志愿的效率和準確度,同時又避免造成網(wǎng)絡(luò)堵塞。考生登錄系統(tǒng)后20分鐘內(nèi)無任何操作,再次進行操作時,系統(tǒng)會進行“考生未登錄”提示,或被強制退出系統(tǒng),且未進行保存過的志愿不會保存。考生須重新登錄系統(tǒng)進行填報。

          7.考生應(yīng)盡早上網(wǎng)填報志愿,避免因網(wǎng)絡(luò)、供電等原因而影響志愿填報。

          8.對填報志愿中系統(tǒng)給出填報有誤提示,考生應(yīng)從批次(段)、計劃性質(zhì)、報考科類、院校代號、專業(yè)代號、選科要求、性別要求,器種、唱法或舞種要求和本人情況等幾方面逐一查找出錯原因。如果志愿信息存在錯誤無法進行確認,請在修改信息后再進行確認,否則可能導(dǎo)致志愿信息無效或不能體現(xiàn)本人最終意愿。

          (四)填報志愿時考生忘記登錄密碼怎么辦?

          遺忘密碼的考生可通過以下途徑進行密碼重置,重置后的密碼為考生身份證號后8位。

          1.通過手機微信重置密碼。考生使用手機添加“河北省教育考試院”微信公眾號,進入密碼找回頁面,通過人臉識別方式自助進行密碼重置。

          2.考生使用能夠訪問互聯(lián)網(wǎng)并裝有攝像頭的計算機,登錄河北省教育考試院普通高校招生考試信息管理與服務(wù)平臺,進入志愿填報或考生信息查詢系統(tǒng),然后進入“密碼重置”頁面,通過人臉識別方式自助進行密碼重置。

          3.到就近報名點重置密碼。考生攜帶本人身份證到任一報名點,通過讀取身份證、人臉識別完成密碼重置。

          提醒考生注意:密碼重置完成后,要及時登錄系統(tǒng)修改初始密碼。考生務(wù)必牢記并妥善保管,避免因密碼泄漏造成不良后果。

          二、志愿填報前考生需要做哪些準備?

          在填報志愿前,要充分了解自己的成績及所處的位次、招生政策、高校招生章程、招生計劃等相關(guān)信息,以節(jié)省填報時間、提升填報效率,提高填報的準確度。

          一是學(xué)習(xí)相關(guān)政策。考生要對當(dāng)年的高考政策有一個整體的把握,清楚招生錄取的相關(guān)辦法和規(guī)定,熟悉各類別的批次設(shè)置、志愿設(shè)置、投檔規(guī)則、錄取辦法以及志愿填報時間和流程。今年是我省高考綜合改革落地之年,考生可登錄省教育廳、省教育考試院網(wǎng)站,查詢《河北省普通高考綜合改革政策解讀“50問”》(網(wǎng)址:https://mp.weixin.qq.com/s/TqyMxWseXo09TFWhXUHIBw)和《河北省2021年普通高校招生考試和錄取工作實施方案解讀》(網(wǎng)址:http://www.hebeea.edu.cn/html/ptgk/tzgg/2020/1229-180049-826.html),了解相關(guān)政策。

          二是查看高校招生計劃。招生計劃內(nèi)容包括計劃性質(zhì)、批次、科類、院校、辦學(xué)類型、專業(yè)、選考科目要求、學(xué)制、學(xué)費、專業(yè)備注等信息。考生可通過河北省教育考試院匯編的《2021年河北省普通高等學(xué)校招生計劃》(物理科目組合/歷史科目組合·對口)進行查詢。

          三是閱讀高校招生章程。考生可登錄高校官方網(wǎng)站或教育部陽光高考信息公開平臺,查閱相關(guān)高校2021年招生章程。招生章程主要內(nèi)容包括:高校全稱、校址(涉及分校、校區(qū)等須注明),層次(本科、專科),辦學(xué)類型(如普通或成人高校、公辦或民辦高校或獨立學(xué)院、高等專科學(xué)校或高等職業(yè)技術(shù)學(xué)校等),招生計劃分配的原則和辦法,預(yù)留計劃數(shù)及使用原則,專業(yè)教學(xué)培養(yǎng)使用的外語語種,身體健康狀況要求,進檔考生錄取規(guī)則(如對考生加分成績的使用、投檔成績相同考生的處理、進檔考生的專業(yè)安排辦法等),學(xué)費標準,家庭經(jīng)濟困難學(xué)生資助政策及有關(guān)程序,頒發(fā)學(xué)歷證書的學(xué)校名稱、證書種類及其他信息,聯(lián)系電話、網(wǎng)址,以及其他須知等。

          四是了解《普通高等學(xué)校招生體檢工作指導(dǎo)意見》。其中規(guī)定了對患有某些疾病或有生理缺陷者不宜報考的專業(yè)。考生應(yīng)根據(jù)體檢結(jié)果,對照體檢工作指導(dǎo)意見和有關(guān)高校的招生章程,避開自己不宜報考的專業(yè)。

          五是了解自己所在的位次。高考成績公布后,省教育考試院將在官網(wǎng)、官微公布當(dāng)年“河北省普通高校招生各類考生成績統(tǒng)計表”。屆時,考生可進行查看,供填報志愿參考。

          六是參考其他資料。包括《全國普通高校在河北招生錄取分數(shù)分布統(tǒng)計2018—2020》《2021年河北省普通高校招生報考指南》《2021年河北省普通高等學(xué)校招生藝術(shù)類報考指南》。其中,《全國普通高校在河北招生錄取分數(shù)分布統(tǒng)計2018—2020》主要內(nèi)容為近三年全國普通高校在河北省招生錄取情況,包括分學(xué)校、分專業(yè)的錄取數(shù)、最高分、最低分、平均分、差值及各專業(yè)錄取分數(shù)分布統(tǒng)計;《2021年河北省普通高校招生報考指南》和《2021年河北省普通高等學(xué)校招生藝術(shù)類報考指南》介紹了我省高考錄取的相關(guān)政策規(guī)定、操作程序和注意事項,并收集整理了近三年高校錄取的相關(guān)數(shù)據(jù)和資料,這些資料為考生填報志愿作參考。

          七是分析研究相關(guān)信息。收集分析相關(guān)高校的往年錄取數(shù)據(jù)等多種信息,結(jié)合自己的學(xué)習(xí)興趣、專業(yè)取向和未來發(fā)展規(guī)劃,綜合考慮,理性選擇。

          八是利用好《2021年河北省普通高校招生考生志愿填報草表》,按照批次、計劃性質(zhì)、科類或資格類型等提前進行志愿預(yù)選。

          三、招生計劃是如何編制的?

          各高校在我省的招生計劃,經(jīng)其教育主管部門審核、匯總后上報教育部,再由教育部分送給我省。我院按照我省的格式對計劃內(nèi)容進行了編排、匯總,由高校核對確認后統(tǒng)一向社會公布。

          2021年我省普通高校招生,普通類、體育類按物理科目組合、歷史科目組合分別編制招生計劃。藝術(shù)類不區(qū)分物理科目組合、歷史科目組合,統(tǒng)一編制招生計劃。對于只招首選科目為歷史的考生或只招首選科目為物理的考生的藝術(shù)類專業(yè),我省根據(jù)院校的要求在招生計劃中予以公布。

          首選科目為物理的普通類、體育類考生,查詢《2021年河北省普通高等學(xué)校招生計劃》(物理科目組合),首選科目為歷史的普通類、體育類考生,查詢《2021年河北省普通高等學(xué)校招生計劃》(歷史科目組合·對口)。為便于考生查閱,藝術(shù)類專業(yè)招生計劃在《2021年河北省普通高等學(xué)校招生計劃》(物理科目組合)和《2021年河北省普通高等學(xué)校招生計劃》(歷史科目組合·對口)中均有編列,但它們是同一計劃,并非物理科目組合和歷史科目組合各自單獨的招生計劃數(shù)(個別專業(yè)單獨注明只招首選科目為歷史或只招首選科目為物理的考生的除外)。按照招生院校要求,對首選科目有要求的藝術(shù)類專業(yè),我省招生計劃中相應(yīng)注明“[只招首選科目為[歷史]考生]”或“[只招首選科目為[物理]考生]”,請考生注意查看,不要填報不符合選考科目要求的專業(yè)。

          對口類招生計劃編制原則和方式與往年相同,對口考生查詢計劃可參考《2021年河北省普通高等學(xué)校招生計劃》(歷史科目組合·對口)。

          提醒考生注意:

          一是考生在志愿填報系統(tǒng)中所填的院校代號、專業(yè)代號等內(nèi)容,均以《2021年河北省普通高等學(xué)校招生計劃》(物理科目組合/歷史科目組合·對口)所公布的為準。未經(jīng)省教育考試院公布的招生高校和計劃,一律不安排在河北省招生。考生要特別注意《招生計劃》中擬報考院校(專業(yè))的計劃性質(zhì)、科類及其所在的錄取批次(段),并在志愿填報時正確選擇。

          二是《招生計劃》中部分院校(專業(yè))后注明了院校(專業(yè))的辦學(xué)地點、學(xué)費標準和外語語種、單科成績等限制條件,也有部分院校沒有注明,但是不代表學(xué)校沒有要求,所以請考生報考前務(wù)必查詢院校招生章程或向招生院校咨詢。在招生過程中,一些院校的計劃內(nèi)容可能有變動,考生在填報志愿前,應(yīng)了解各招生院校(專業(yè))的具體情況和報考要求。

          三是為使考生更加清楚地了解高校,今年招生計劃的院校名稱后面添加了辦學(xué)類型。

          四、在查閱招生計劃時要注意哪些問題?

          考生查閱招生計劃時,需注意選考科目、辦學(xué)性質(zhì)、專業(yè)備注內(nèi)對考生性別、外語語種、身體條件和面試等方面的要求。招生計劃展現(xiàn)給考生的是同一院校下多個專業(yè),考生填報順序志愿時應(yīng)先填寫院校代號,再填寫不超過6個專業(yè)代號,并根據(jù)自身實際決定是否勾選專業(yè)服從調(diào)劑選項,從而構(gòu)成1個志愿;考生填報“專業(yè)(類)+學(xué)校”平行志愿時應(yīng)先填寫院校代號,再填寫1個專業(yè)代號,從而構(gòu)成1個志愿。

          五、改革后的普通高校招生錄取依據(jù)有什么變化?

          從2021年起,我省普通高校招生依據(jù)統(tǒng)一高考和高中學(xué)業(yè)水平選擇性考試成績,參考綜合素質(zhì)評價進行錄取。

          六、綜合素質(zhì)評價在錄取時如何使用?

          普通高中學(xué)生綜合素質(zhì)評價作為高校招生錄取的參考依據(jù),投檔時,我省將考生的綜合素質(zhì)評價情況提供給招生高校。具體使用辦法由招生高校在招生章程中予以明確。

          七、今年志愿填報和往年相比有什么變化?

          一是高校專業(yè)增加了選考科目要求。比如,某高校某專業(yè)要求考生首選科目為物理,再選科目為化學(xué),只有選科時選擇這兩個科目的考生才能填報,否則為無效志愿。二是平行志愿批次的志愿單位、數(shù)量有所調(diào)整。志愿填報由以“學(xué)校”為單位,變?yōu)橐浴皩I(yè)(類)+學(xué)校”為單位,即一所院校一個招生專業(yè)(類)為一個志愿,不再設(shè)專業(yè)服從調(diào)劑選項。實行平行志愿的批次,普通類最多可填報96個志愿,藝術(shù)類、體育類最多可填報70個志愿。

          八、院校招生專業(yè)對再選科目有幾種要求?如何查詢?

          高校對再選科目要求分為四種:一是不提再選科目要求的,符合首選科目要求的考生均可報考;二是提出1門再選科目要求的,考生必須選考該科目方可報考,如某校某專業(yè)對化學(xué)科目提出要求,符合首選科目要求且選考化學(xué)的考生才能報考;三是提出2門再選科目要求且均須選考的,考生須同時選考這2門科目方可報考,如某校某專業(yè)對化學(xué)和生物科目提出要求,符合首選科目要求且同時選考化學(xué)和生物的考生才能報考;四是提出2門再選科目要求且只需選考其中1門的,考生選考該2門科目中的任意1門即可報考,如某校某專業(yè)要求考生選考化學(xué)或生物科目,符合首選科目要求且只要再選科目中有化學(xué)或生物的考生即可報考。

          考生可以通過以下兩種途徑查詢高校相關(guān)選考科目要求:

          (1)登錄各高校官方網(wǎng)站進行查詢。

          (2)通過《2021年河北省普通高等學(xué)校招生計劃》進行查詢。

          九、如何理解“專業(yè)(類)+學(xué)校”志愿模式變化?

          我省將在普通類的本科提前批B段、本科批、專科批,藝術(shù)類的本科提前批B段、專科提前批部分專業(yè),體育類的本科提前批B段、專科提前批實行”專業(yè)(類)+學(xué)校”的平行志愿,與原來以學(xué)校為單位的志愿模式相比發(fā)生了變化。

          一是填報的基本單位發(fā)生了變化。志愿填報由以“學(xué)校”為單位,變?yōu)橐浴皩I(yè)(類)+學(xué)校”為單位,即一所院校一個招生專業(yè)(類)為一個志愿。比如原來志愿模式下,要報考北京大學(xué)的數(shù)學(xué)、物理、化學(xué)3個專業(yè),只需填報在北京大學(xué)1個志愿單位下即可,新的志愿模式下,則需要填報北京大學(xué)+數(shù)學(xué)、北京大學(xué)+物理、北京大學(xué)+化學(xué)3個志愿單位。

          二是志愿數(shù)量發(fā)生了變化。新的志愿模式下,普通類每次最多可填報96個志愿,藝術(shù)類、體育類每次最多可填報70個志愿。

          三是增加了選考科目要求。改革前考生填報志愿時,同一個科類,考生基本可以填報擬報考學(xué)校的所有專業(yè)(有特殊要求的除外)。改革后,考生填報志愿須符合擬報考學(xué)校專業(yè)的選考科目要求,不符合要求的不能填報。

          四是不再設(shè)專業(yè)服從調(diào)劑選項。以前的志愿模式下,部分考生因不服從院校的專業(yè)調(diào)劑,而被投檔院校退檔。”專業(yè)(類)+學(xué)校”模式取消了專業(yè)調(diào)劑,考生不必擔(dān)心被調(diào)劑到不喜歡的專業(yè),也不用擔(dān)心出現(xiàn)“因不服從專業(yè)調(diào)劑而退檔”的情況,但需要注意的是,有些專業(yè)對身體條件、語種等另做要求,考生即便被投檔,高校也可能因考生不符合招生章程中的規(guī)定而退檔。

          下面以普通類本科批志愿設(shè)置為例,對比一下改革前和改革后志愿設(shè)置的變化:

          十、“專業(yè)(類)+學(xué)校”平行志愿投檔原則是什么?

          “專業(yè)(類)+學(xué)校”平行志愿投檔原則為“分數(shù)優(yōu)先、遵循志愿、一次投檔、不再補檔”,將控制線上未錄取的有志愿考生,結(jié)合高校各專業(yè)(類)要求,依據(jù)高校調(diào)檔比例確定投檔考生數(shù),普通類按高考文化總成績(含政策性加分),藝術(shù)類、體育類按綜合成績,從高分到低分排序,遵循考生的志愿順序依次投檔,由高校擇優(yōu)錄取。

          具體地講,就是先從排在第一位的考生開始,計算機根據(jù)該生填報的1、2、3、4、5……等多個平行志愿,從第1個志愿開始依次檢索,如果第1個志愿有空額就投檔,如已滿額,則檢索第2個志愿,依此類推。一旦投檔,該生后面的志愿即失效。然后再檢索排在第二位的考生……直到所有計劃滿額或者沒有符合投檔條件的考生為止。如果某一考生填報的所有志愿都不符合投檔條件,則不能被投檔。

          十一、對”專業(yè)(類)+學(xué)校”平行志愿認識誤區(qū)有哪些?

          一般來說對平行志愿的認識誤區(qū)有三個:

          誤區(qū)一:認為可以一檔多投或多次投檔。在同一批(段)考生一次可以填報多個學(xué)校專業(yè)(類)志愿,但在實際投檔過程中,投檔機會最多只有一次,也就是說,即使有多個志愿符合投檔要求,在這些志愿中,只能投檔到排在前面的那一個,而且一旦投檔,其余志愿隨即失效,不再投檔。投檔后因某種原因被退檔,即使后面還有符合投檔條件的志愿,也不再投檔。

          誤區(qū)二:認為平行志愿沒有先后順序。對考生個人來說,平行志愿是有先后順序的。平行志愿的檢索順序就是考生所填報的1、2、3、4、5……志愿順序,所以考生一定要精心安排志愿順序,把最心儀的志愿填在靠前的位置。

          誤區(qū)三:認為實行平行志愿后沒有了風(fēng)險。仍然會有風(fēng)險,主要有以下三種原因:平行志愿間沒有拉開梯度。如果考生定位不準確,一味追求最理想的高校和專業(yè),志愿填報過高(比如多個平行院校志愿之間沒有拉開梯度),就可能導(dǎo)致所填報的幾個志愿全部落空。填報的志愿過少。如果考生沒有充分利用選擇機會,只填報了較少數(shù)量的志愿,就有可能因為高考成績未達到招生院校的投檔線而不能被錄取。考生的外語語種、身體條件等因素不符合高校要求的,都有可能造成退檔,這些因素由高校根據(jù)招生需要確定,并在高校招生章程中公布。投檔是以考生成績和志愿順序作為依據(jù)的,考生一旦投到某個高校的專業(yè),但不符合高校招生章程中該專業(yè)的具體要求,就會造成退檔。因此考生在填報志愿前一定要認真查看高校招生章程。

          十二、填報“專業(yè)(類)+學(xué)校”平行志愿有哪些建議?

          一是認真閱讀《2021年河北省普通高等學(xué)校招生計劃》,包括院校名稱、辦學(xué)性質(zhì)、專業(yè)(專業(yè)類)、層次、選考科目要求、學(xué)制、學(xué)費、計劃數(shù)等。

          二是分析研究相關(guān)數(shù)據(jù)。受“專業(yè)(類)+學(xué)校”平行志愿投檔方式的實施以及高校對選考科目的要求等影響,往年的錄取分數(shù)和位次將不再具有直觀的參考意義,但從先期改革省份情況看,高校往年錄取數(shù)據(jù)仍具有一定參考價值。在填報志愿時,考生要依據(jù)自己的成績和位次,綜合考慮相關(guān)數(shù)據(jù)信息,特別是往年招生院校各專業(yè)的錄取數(shù)據(jù),合理選擇擬填報的院校和專業(yè)。

          三是選擇確定填報意向。考生首先要根據(jù)自己的選考科目、成績位次、興趣愛好、身體狀況等因素,認真閱讀院校的招生章程(詳細了解院校招生政策、錄取規(guī)則、學(xué)科優(yōu)勢、專業(yè)設(shè)置、地理位置等方面信息),詳細了解招生院校各專業(yè)(類)招生計劃(包括選科要求、身體條件要求、學(xué)費標準、外語語種要求等),明確自己立志攻讀的專業(yè)范圍和院校范圍。

          四是認真研讀高校的招生章程。要特別注意各專業(yè)對考生的要求,如身體條件、外語語種、單科成績、綜合素質(zhì)評價、選考科目要求等是否符合報考條件。

          五是合理安排志愿順序。考生要把心儀的志愿填在靠前的位置,志愿之間要有合理梯度,不宜全部填報高分段也不必全部填報低分段志愿。考生應(yīng)盡量填滿志愿,多一個志愿,可能就多一分錄取機會。

          十三、往年的招生錄取數(shù)據(jù)如何查詢?

          一是登錄擬填報院校官方網(wǎng)站進行查詢。

          二是通過省教育考試院匯編的《全國普通高校在河北招生錄取分數(shù)分布統(tǒng)計2018—2020》《2021年河北省普通高校招生報考指南》和《2021年河北省普通高等學(xué)校招生藝術(shù)類報考指南》。這些資料收集整理了近三年高校錄取的相關(guān)數(shù)據(jù)和資料。

          三是通過河北省高考志愿填報智能參考系統(tǒng)查詢。考生憑使用碼通過河北省招生考試信息服務(wù)網(wǎng)(http://www.hebeeb.com/)登錄使用。詳見第三十二條。

          十四、對口類志愿填報和往年比有變化嗎,其錄取批次和志愿是怎么設(shè)置的?

          對口類志愿填報和往年比沒有任何變化。仍分為對口本科批和對口專科批兩個批次,均設(shè)1次集中填報志愿和1次征集志愿,實行以“學(xué)校”為單位的平行志愿投檔模式,每個志愿可填報5所院校(每所院校設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項)。其中,對口本科批隨本科提前批B段填報志愿、錄取,對口專科批隨專科提前批填報志愿、錄取。

          考生如被上一批次高校錄取,不能再參加下一批次高校的錄取;如未被上一批次高校錄取,其參加下一批次高校錄取的機會不受影響。

          十五、物理科目組合和歷史科目組合各錄取批次及志愿是如何設(shè)置的?

          可分為普通類、藝術(shù)類、體育類,分別進行批次設(shè)置,實行平行志愿和順序志愿兩種模式。

          (一)普通類。錄取批次分為本科提前批、本科批、專科提前批、專科批等四個批次。一是本科提前批。分為A、B、C三段,每段為一個獨立的小批次,依次進行錄取。其中,本科提前批A段包括有政治考察、面試、體檢等特殊要求的國家專項計劃、軍隊、公安、司法等本科專業(yè)。實行以學(xué)校為單位的順序志愿模式。設(shè)1次集中填報志愿和1次征集志愿,每次可填報1所學(xué)校,每所學(xué)校設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。本科提前批B段包括除本科提前批A段以外的其他國家專項計劃、公費師范生和免費醫(yī)學(xué)定向生等本科專業(yè)。實行以“專業(yè)(類)+學(xué)校”為單位的平行志愿模式,一所院校一個招生專業(yè)(類)為一個志愿。設(shè)1次集中填報志愿和1次征集志愿,每次最多可填報96個志愿。本科提前批C段包括高水平運動隊、高水平藝術(shù)團、高校專項計劃、定向就業(yè)招生等特殊類型招生本科專業(yè)。實行以學(xué)校為單位的順序志愿模式。只設(shè)1次集中填報志愿,不進行志愿征集,可填報1所學(xué)校,設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。二是本科批。包括未列入本科提前批的普通類本科專業(yè)、地方專項計劃、本科預(yù)科班(包括少數(shù)民族預(yù)科班、邊防軍人子女預(yù)科班)等。實行以“專業(yè)(類)+學(xué)校”為單位的平行志愿模式,一所院校一個招生專業(yè)(類)為一個志愿。設(shè)1次集中填報志愿和1次征集志愿,每次最多可填報96個志愿。三是專科提前批。包括有面試、體檢等特殊要求的公安、司法等專科專業(yè)。實行以學(xué)校為單位的順序志愿模式。設(shè)1次集中填報志愿和1次征集志愿,每次可填報1所學(xué)校,每所學(xué)校設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。四是專科批。包括未列入專科提前批的普通類專科專業(yè)。實行以“專業(yè)(類)+學(xué)校”為單位的平行志愿模式,一所院校一個招生專業(yè)(類)為一個志愿。設(shè)1次集中填報志愿和2次征集志愿,每次最多可填報96個志愿。

          (二)藝術(shù)類。藝術(shù)類招生分本科提前批和專科提前批兩個批次。每次志愿填報時(集中填報志愿或征集志愿),同一批次只能選擇一個科類填報,各科類不能同時兼報。一是本科提前批。分為A、B、C三段,每段為一個獨立的小批次,依次進行錄取。本科提前批A段包括教育部批準的獨立設(shè)置藝術(shù)高校、參照執(zhí)行高校的有關(guān)藝術(shù)類本科專業(yè),原“211工程”高校的藝術(shù)類校考本科專業(yè),有特殊要求無法實行平行志愿投檔的藝術(shù)類統(tǒng)考和校際聯(lián)考等本科專業(yè)。實行以學(xué)校為單位的順序志愿模式。設(shè)1次集中填報志愿和1次征集志愿,每次可填報1所學(xué)校,每所學(xué)校設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。本科提前批B段包括使用河北省藝術(shù)統(tǒng)考或校際聯(lián)考成績作為專業(yè)成績進行錄取,并執(zhí)行我省平行志愿統(tǒng)一投檔原則的藝術(shù)類本科專業(yè)。實行以“專業(yè)(類)+學(xué)校”為單位的平行志愿模式,一所院校一個招生專業(yè)(類)為一個志愿。設(shè)1次集中填報志愿和1次征集志愿,每次最多可填報70個志愿。本科提前批C段包括除本科提前批A段、本科提前批B段以外的其他藝術(shù)類本科專業(yè)。實行以學(xué)校為單位的順序志愿模式。設(shè)1次集中填報志愿和1次征集志愿,每次可填報1所學(xué)校,每所學(xué)校設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。二是專科提前批。包括藝術(shù)類專科專業(yè)。分平行志愿和順序志愿兩種模式。其中,使用河北省藝術(shù)統(tǒng)考或校際聯(lián)考成績作為專業(yè)成績進行錄取的,實行以“專業(yè)(類)+學(xué)校”為單位的平行志愿模式,一所院校一個招生專業(yè)(類)為一個志愿,設(shè)1次集中填報志愿和1次征集志愿,每次最多可填報70個志愿;使用藝術(shù)校考成績作為專業(yè)成績進行錄取的,實行以學(xué)校為單位的順序志愿模式,設(shè)1次集中填報志愿和1次征集志愿,每次可填報1所學(xué)校,每所學(xué)校設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。

          (三)體育類。體育類招生分本科提前批和專科提前批兩個批次。一是本科提前批。分為A、B兩段,每段為一個獨立的小批次,依次進行錄取。本科提前批A段包括河北體育學(xué)院少數(shù)民族傳統(tǒng)體育項目。實行以學(xué)校為單位的順序志愿模式。設(shè)1次集中填報志愿和1次征集志愿。本科提前批B段包括使用河北省普通體育類專業(yè)考試成績作為專業(yè)成績進行錄取的體育類本科專業(yè)。實行以“專業(yè)(類)+學(xué)校”為單位的平行志愿模式。設(shè)1次集中填報志愿和1次征集志愿。一所院校一個招生專業(yè)(類)為一個志愿,每次最多可填報70個志愿。二是專科提前批。包括使用河北省普通體育類專業(yè)考試成績作為專業(yè)成績進行錄取的體育類專科專業(yè)。實行以“專業(yè)(類)+學(xué)校”為單位的平行志愿模式,一所院校一個招生專業(yè)(類)為一個志愿。設(shè)1次集中填報志愿和1次征集志愿,每次最多可填報70個志愿。

          考生如被上一批次(段)高校錄取,不能再參加下一批次(段)高校的錄取;如未被上一批次(段)高校錄取,其參加下一批次(段)高校錄取的機會不受影響。

          十六、藝術(shù)類、體育類考生的綜合成績是如何構(gòu)成的?

          藝術(shù)類、體育類綜合成績的構(gòu)成:

          (1)美術(shù)類、音樂類(含聲樂類和器樂類)、舞蹈類、書法學(xué)、服裝表演類:綜合成績=高考文化總成績(含政策性加分)×0.3+(專業(yè)成績÷專業(yè)滿分)×750×0.7,結(jié)果四舍五入保留3位小數(shù)。其中,美術(shù)類專業(yè)滿分300分,音樂類(含聲樂類和器樂類)、舞蹈類、書法學(xué)專業(yè)滿分均為200分,服裝表演類專業(yè)滿分100分。

          (2)戲劇與影視學(xué)類、播音與主持藝術(shù):綜合成績=高考文化總成績(含政策性加分)×0.7+(專業(yè)成績÷專業(yè)滿分)×750×0.3,結(jié)果四舍五入保留3位小數(shù)。戲劇與影視學(xué)類、播音與主持藝術(shù)專業(yè)滿分均為200分。

          (3)體育類:綜合成績=高考文化總成績(含政策性加分)×0.3+(專業(yè)成績÷專業(yè)滿分)×750×0.7,結(jié)果四舍五入保留3位小數(shù)。體育類專業(yè)滿分400分。

          十七、藝術(shù)類、體育類考生可以兼報普通類專業(yè)嗎?

          藝術(shù)類和體育類考生,可以兼報普通類專業(yè),但每次志愿填報時(集中填報志愿或征集志愿),同一批次(段)只能選擇一個類別填報。

          十八、填報軍隊院校志愿應(yīng)注意哪些事項?

          今年軍隊院校招生的變化主要有兩點,一是考生在公布高考成績后,于6月26日12時至6月27日12時填報軍隊院校志愿。二是根據(jù)教育部、中央軍委政治工作部、中央軍委訓(xùn)練管理部《關(guān)于做好2021年軍隊院校招收普通高中畢業(yè)生工作的通知》(軍訓(xùn)〔2021〕112號)精神,報考軍隊院校考生高中階段體質(zhì)測試成績需達到及格以上(即普通高中學(xué)業(yè)水平合格性考試體育與健康科目成績?yōu)椤昂细瘛保?yīng)屆生體育與健康科目成績由省中考中心提供,合格考生無需提供相關(guān)成績證明,考生可通過河北省普通中等教育考試服務(wù)中心網(wǎng)站(https://www.hebeixk.com)查詢本人的體育與健康科目成績是否合格。往屆生持學(xué)考成績合格證復(fù)印件,或通過河北省普通中等教育考試服務(wù)中心網(wǎng)站(https://www.hebhk.com)打印的含有本人體育與健康科目成績合格的截圖,或畢業(yè)學(xué)校出具的加蓋學(xué)校公章的相關(guān)成績合格證明,在考生參加軍檢時向相應(yīng)軍檢站提交。

          軍隊院校招生計劃安排在本科提前批A段,實行順序志愿投檔,設(shè)1次集中填報志愿和1次征集志愿,考生每次可填報1所學(xué)校,每所學(xué)校設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。

          已完成軍隊院校(專業(yè))志愿填報的考生,仍可在規(guī)定時間填報包括本科提前批A段在內(nèi)的普通院校(專業(yè))志愿。其中,通過省軍區(qū)戰(zhàn)備建設(shè)局組織的政治考核和軍檢合格的考生,其軍隊院校(專業(yè))志愿生效,本科提前批A段的普通院校(專業(yè))志愿無效;未通過省軍區(qū)戰(zhàn)備建設(shè)局組織的政治考核或軍檢不合格的考生,其軍隊院校(專業(yè))志愿無效,本科提前批A段的普通院校(專業(yè))志愿生效。

          陸軍工程大學(xué)安排在本科提前批A段的定向人防計劃以及空軍軍醫(yī)大學(xué)和海軍軍醫(yī)大學(xué)安排在本科批的普通類招生計劃,考生不用參加政治考核和軍事職業(yè)適應(yīng)性檢測,入學(xué)后無軍籍,不享受軍官學(xué)員相關(guān)待遇。這兩類計劃隨相應(yīng)批次普通類專業(yè)進行填報,不屬于6月26日12時至6月27日12時軍隊院校志愿填報范圍。

          具體要求詳見軍隊院校招生相關(guān)文件,或及時關(guān)注省教育考試院官方網(wǎng)站查詢有關(guān)招生辦法。

          十九、填報公安院校志愿應(yīng)注意哪些事項?

          報考公安院校的考生須參加由省公安廳組織的政治考察、面試、體檢和體能測評且合格。公安院校招生計劃安排在本科提前批A段和專科提前批,實行順序志愿投檔,設(shè)1次集中填報志愿和1次征集志愿,每批(段)每次只能填報1所院校,每所學(xué)校設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。公安院校的國家專項計劃與其他公安類本科專業(yè)都編列在本科提前批A段,計劃性質(zhì)均為非定向,這兩類計劃分開編列,公安類的國家專項計劃統(tǒng)一編排在所有普通類公安計劃之后,同時具有相應(yīng)資格的考生只能選擇一類填報。

          具體要求詳見公安院校招生相關(guān)文件,或及時關(guān)注省教育考試院官方網(wǎng)站查詢有關(guān)招生辦法。

          二十、如何填報定向就業(yè)招生志愿?

          定向就業(yè)招生計劃單列,實行順序志愿投檔,每個批次(段)只能填報1所院校志愿。解放軍陸軍工程大學(xué)定向人防計劃安排在本科提前批A段,清華大學(xué)、東北大學(xué)秦皇島分校的定向就業(yè)計劃安排在本科提前批C段,詳見當(dāng)年招生計劃。

          二十一、高水平運動隊招生如何填報志愿?

          報考高水平運動隊的考生,須通過招生院校考核合格且經(jīng)教育部“陽光高考”信息平臺公示無異議后方可填報。高水平運動隊在本科提前批C段錄取,實行順序志愿,設(shè)1次集中填報志愿,不進行志愿征集。可填報1所學(xué)校,設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。

          二十二、高水平藝術(shù)團招生如何填報志愿?

          報考高水平藝術(shù)團的考生,須通過招生院校考核合格且經(jīng)教育部“陽光高考”信息平臺公示無異議后方可填報。高水平藝術(shù)團在本科提前批C段錄取,實行順序志愿,設(shè)1次集中填報志愿,不進行志愿征集。可填報1所學(xué)校,設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。

          二十三、國家專項計劃招生如何填報志愿?

          國家專項計劃志愿安排在本科提前批A段和B段。其中,有政治考察、面試、體檢等特殊要求的國家專項計劃安排在本科提前批A段,其他國家專項安排在本科提前批B段。通過國家專項計劃資格審核的考生方可填報。

          本科提前批A段的國家專項計劃實行順序志愿,設(shè)集中填報志愿和征集志愿,每次只能填報1所學(xué)校,設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。本科提前批B段的國家專項計劃實行平行志愿,設(shè)集中填報志愿和征集志愿,每次最多可填報96個志愿,與免費醫(yī)學(xué)定向生、公費師范生同批一起填報,同批一起錄取。

          二十四、高校專項計劃招生如何填報志愿?

          高校專項計劃列在本科提前批C段,實行順序志愿,設(shè)1次集中填報志愿,不進行志愿征集,可填報1所學(xué)校,設(shè)6個專業(yè)志愿和1個專業(yè)服從調(diào)劑選項。經(jīng)有關(guān)高校考核合格且在教育部“陽光高考”信息平臺公示無異議的考生方可填報。

          二十五、地方專項計劃招生如何填報志愿?

          地方專項計劃安排在本科批,設(shè)集中填報志愿和征集志愿,與其他普通類學(xué)校同批一起填報,同批一起錄取,每次最多可填報96個志愿。通過地方專項計劃資格審核的考生方可填報。

          二十六、如何填報公費師范生(含優(yōu)師專項)志愿?

          教育部直屬部分師范院校和我省部分師范院校繼續(xù)安排公費師范生招生。普通類公費師范生安排在本科提前批B段。今年國家在我省新增優(yōu)師專項,該計劃屬于公費師范生范疇,是為中西部欠發(fā)達地區(qū)定向培養(yǎng)教師的專項計劃,面向全省招生,分為國家優(yōu)師專項(部委屬師范大學(xué)承擔(dān))和地方優(yōu)師專項(河北師范大學(xué)和河北民族師范學(xué)院承擔(dān)),面向我省特困片區(qū)縣和扶貧重點縣就業(yè)。普通類的優(yōu)師專項列在普通類本科提前批B段,編列到公費師范生類,單列院校代號,院校名稱后單獨標注“優(yōu)師專項”,與公費師范生、免費醫(yī)學(xué)定向生、國家專項計劃一起實行平行志愿。除以上普通類公費師范生(含優(yōu)師專項)招生之外,藝術(shù)、體育、高校專項計劃等招生類型的公費師范生(含優(yōu)師專項)安排在相應(yīng)類別和批次。考生被公費師范生(含優(yōu)師專項)錄取后須簽訂協(xié)議,詳情請咨詢有關(guān)院校。

          二十七、如何填報預(yù)科班志愿?

          預(yù)科班招生包括少數(shù)民族本科預(yù)科班和邊防軍人子女預(yù)科班。含在普通本科批內(nèi),設(shè)集中填報志愿和征集志愿,與其他普通類學(xué)校同批一起填報,同批一起錄取,每次最多可填報96個志愿。

          其中少數(shù)民族本科預(yù)科班只招收少數(shù)民族考生,邊防軍人子女預(yù)科班只招收通過邊防軍人子女資格審查的考生。

          二十八、強基計劃有關(guān)注意事項?

          報考強基計劃的考生無需在我省志愿填報系統(tǒng)填報強基計劃志愿,按有關(guān)試點高校《招生簡章》的要求報考,由高校確定錄取結(jié)果。我省根據(jù)高校確定的本省擬錄取考生名單,在提前批錄取開始前辦理錄取備案手續(xù)。強基計劃考生可參加我省其他各類高考志愿正常填報,如被強基計劃錄取,將不再參加其他各類型投檔和錄取工作。

          二十九、投檔時,考生成績相同時如何排序?

          普通類:當(dāng)遇到多名考生高考文化總成績(含政策性加分)相同時,依次按語文數(shù)學(xué)兩門成績之和、語文數(shù)學(xué)兩門中的單科最高成績、外語單科成績、首選科目單科成績、再選科目單科最高成績、再選科目單科次高成績由高到低排序投檔;如仍相同,比較考生志愿順序,順序在前者優(yōu)先投檔,志愿順序相同則全部投檔,是否錄取由高校決定。

          軍隊院校、綜合評價招生等有特殊投檔要求的,按照有關(guān)文件執(zhí)行。

          藝術(shù)類、體育類:實行平行志愿模式的批次,當(dāng)遇到多名考生綜合成績相同時,依次按高考文化總成績(含政策性加分)、語文數(shù)學(xué)兩門成績之和、語文數(shù)學(xué)兩門中的單科最高成績、外語單科成績、首選科目單科成績、再選科目單科最高成績、再選科目單科次高成績由高到低排序投檔;如仍相同,比較考生志愿順序,順序在前者優(yōu)先投檔,志愿順序相同則全部投檔,是否錄取由高校決定。

          三十、填報志愿時考生如何對待優(yōu)惠加分政策?

          對具備加分資格的考生,我省按照加分后的分數(shù)投檔。具備國家加分項目資格的考生可在其統(tǒng)考成績總分基礎(chǔ)上增加分值投檔,由高校審查決定是否錄取。具備我省地方加分項目資格的考生,加分范圍只適用于我省高校省內(nèi)招生,在考生文化統(tǒng)考成績總分基礎(chǔ)上增加分值投檔,由高校審查決定是否錄取。對于同時符合多種加分條件的考生,投檔時,報考省外院校的使用國家加分最高一項,報考河北省院校的使用國家加分與省內(nèi)加分中最高一項。根據(jù)教育部有關(guān)規(guī)定,所有高考加分項目及分值均不得用于高校不安排分省招生計劃的藝術(shù)類專業(yè)、高水平藝術(shù)團、高水平運動隊、高校專項計劃等招生項目。錄取時是否考慮加分因素,按院校的有關(guān)規(guī)定執(zhí)行。由于部分院校不承認或部分承認優(yōu)惠加分政策,因此,享有優(yōu)惠加分政策投檔的考生,有可能因?qū)嶋H文化成績較低而被院校退檔。請考生在填報志愿前,務(wù)必認真閱讀有關(guān)院校《招生章程》或向院校咨詢。

          三十一、志愿填報時間截止后還可以補報志愿嗎?

          不接受任何形式的補報志愿。志愿填報系統(tǒng)將按照規(guī)定的志愿填報時間準時開放和關(guān)閉,考生須按照有關(guān)操作流程,在規(guī)定時間內(nèi)完成志愿填報。

          三十二、什么是河北省高考志愿填報智能參考系統(tǒng)?有哪些功能?

          該系統(tǒng)是集專業(yè)測試、信息查詢、志愿智能選擇等功能的一站式輔助咨詢服務(wù)系統(tǒng)。系統(tǒng)將在成績公布后開放使用,可為河北省普通高校招生普通類本科專業(yè)(不含本科提前批)志愿填報提供參考。考生只需“錄信息”“挑專業(yè)”“排順序”“導(dǎo)報表”四步,系統(tǒng)即可給出志愿填報參考建議。考生憑使用碼通過河北省招生考試信息服務(wù)網(wǎng)(http://www.hebeeb.com/)登錄使用。

          6月23日后為模擬試用期,模擬數(shù)據(jù)在系統(tǒng)正式上線后清除。6月25日成績公布后,系統(tǒng)將正式上線。

          技術(shù)服務(wù)熱線:13231165075/15373010897

          (河北省教育考試院)


          主站蜘蛛池模板: 一本AV高清一区二区三区| 亚洲天堂一区二区| 无码少妇一区二区性色AV| 亚洲一区二区三区在线播放| 成人无码精品一区二区三区| 国产精品一区二区久久沈樵| 亚洲国产精品成人一区| 夜夜嗨AV一区二区三区| 五月婷婷一区二区| 国产女人乱人伦精品一区二区 | 国产高清视频一区三区| 无码人妻精品一区二区三区东京热| 国产精品无码一区二区三区电影| 精品无码AV一区二区三区不卡| 亚洲av无一区二区三区| 福利一区福利二区| 久久一区二区三区免费播放| 免费av一区二区三区| 国产精品视频免费一区二区| 日本美女一区二区三区| 色欲AV蜜臀一区二区三区| 极品尤物一区二区三区| 波多野结衣中文字幕一区| 亚洲熟妇av一区二区三区漫画| 日本片免费观看一区二区| 日本v片免费一区二区三区 | 日韩有码一区二区| 夜色福利一区二区三区| 国产香蕉一区二区精品视频| 国产成人精品一区二区三在线观看| 精品伦精品一区二区三区视频| 亚洲美女一区二区三区| 无码精品人妻一区| 日本激情一区二区三区| 午夜无码一区二区三区在线观看| 肉色超薄丝袜脚交一区二区| 日本一区二区三区免费高清在线| 秋霞无码一区二区| 亚洲毛片不卡av在线播放一区| 精品深夜AV无码一区二区| 日亚毛片免费乱码不卡一区|