整合營銷服務(wù)商

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

          免費(fèi)咨詢熱線:

          JavaScript 中 this 的錯誤認(rèn)識、綁定規(guī)則、常見問題講解

          者:五月君

          轉(zhuǎn)發(fā)鏈接:https://mp.weixin.qq.com/s/8f1f3IkOwqK0u5AEuTemlg

          ames對象

          應(yīng)用程序或工作簿中的所有**Name** 對象的集合。

          每一個 Name 對象都代表一個單元格區(qū)域的定義名稱。 名稱可以是內(nèi)置名稱, 例如 Database、Print_Area 和 Auto_Open (或 custom names)。

          RefersTo 參數(shù)必須以 A1 樣式表示法指定,包括必要時使用的美元符 ($)。 例如,如果在 Sheet1 上選定了單元格 A10,并且通過將 RefersTo 參數(shù)“=Sheet1!A1:B1”而定義了一個名稱,那么該新名稱實(shí)際上指向單元格區(qū)域 A10:B10(因?yàn)橹付ǖ氖窍鄬σ茫?若要指定絕對引用,請使用“=Sheet1!$A:$B”。

          方法

          Add方法:為單元格區(qū)域定義新名稱。

          Item 方法:從Names集合中返回單個**Name** 對象。

          屬性

          Application 屬性:在不使用對象識別符的情況下使用時, 此屬性返回代表 Microsoft Excel 應(yīng)用程序的**Application** 對象。 如果與對象識別符一起使用,則此屬性返回代表指定對象的創(chuàng)建者的 Application 對象(可以將此屬性與 OLE 自動化對象一起使用以返回該對象的應(yīng)用程序)。 只讀。

          Count 屬性:返回一個 Long 值,它表示集合中對象的數(shù)量。

          Creator 屬性:返回一個 32 位整數(shù),該整數(shù)指示在其中創(chuàng)建了此對象的應(yīng)用程序。 只讀 Long。

          Parent 屬性:返回指定對象的父對象。 只讀。

          Name 對象

          代表單元格區(qū)域的定義名。 名稱可以是內(nèi)置名稱, 例如 Database、Print_Area 和 Auto_Open (或 custom names)。

          方法

          Delete 方法:刪除對象

          屬性

          Application 屬性:在不使用對象識別符的情況下使用時, 此屬性返回代表 Microsoft Excel 應(yīng)用程序的**Application** 對象。 如果與對象識別符一起使用,則此屬性返回代表指定對象的創(chuàng)建者的 Application 對象(可以將此屬性與 OLE 自動化對象一起使用以返回該對象的應(yīng)用程序)。 只讀。

          Category 屬性:返回或設(shè)置指定名稱的類別中的宏語言。 名稱必須引用自定義的函數(shù)或命令。 讀/寫 String。

          CategoryLocal 屬性:返回或設(shè)置指定名稱的類別中的用戶語言名稱引用自定義的函數(shù)或命令。 讀/寫 String。

          Comment 屬性:返回或設(shè)置與名稱相關(guān)聯(lián)的批注。 讀/寫 String。

          Creator 屬性:返回一個 32 位整數(shù),該整數(shù)指示在其中創(chuàng)建了此對象的應(yīng)用程序。 只讀 Long。

          Index 屬性:返回一個 long 類型值,該值代表相似對象的集合中對象的索引號。

          MacroType 屬性:返回或設(shè)置名稱所引用的對象。 讀/寫**XlXLMMacroType**。 xlXLMMacroType可以是下列xlXLMMacroType常量之一。 ||xlCommand。 名稱是指用戶定義的宏。 ||xlFunction。 名稱是指用戶定義的函數(shù)。 ||xlNotXLM。 名稱不引用函數(shù)或宏。

          Name 屬性:返回或設(shè)置一個String值,它代表對象的名稱。

          NameLocal 屬性:返回或設(shè)置中的語言的用戶對象的名稱。 讀/寫 String。

          Parent 屬性:返回指定對象的父對象。 只讀。

          RefersTo 屬性:用宏語言以 A1 樣式表示法返回或設(shè)置名稱所引用的公式(以等號開頭)。 讀/寫 String。

          RefersToLocal 屬性:返回或設(shè)置名稱引用的公式。 公式中的用戶語言和處于 A1 樣式表示法,開頭等號。 讀/寫 String。

          RefersToR1C1 屬性:返回或設(shè)置名稱引用的公式。 公式中的宏,語言和處于 R1C1 樣式表示法,開頭等號。 讀/寫 String。

          RefersToR1C1Local 屬性:返回或設(shè)置名稱引用的公式。 此公式中的用戶語言和處于 R1C1 樣式表示法,開頭等號。 讀/寫 String。

          RefersToRange 屬性:返回一個由Name對象引用的**Range** 對象。 只讀。

          ShortcutKey 屬性:返回或設(shè)置定義為自定義 Microsoft Excel 4.0 宏命令的名稱的快捷鍵。 讀/寫 String。

          ValidWorkbookParameter 屬性:如果指定的Name對象是有效的工作簿參數(shù),則返回True 。 只讀 Boolean。

          Value 屬性:返回或設(shè)置一個String值,該值代表公式的規(guī)定名稱去引用。

          Visible 屬性:返回或設(shè)置一個布爾值, 確定對象是否可見。 讀/寫。如果將某個名稱的Visible屬性設(shè)置為False, 則該名稱將不會出現(xiàn)在 "定義名稱" 對話框中。

          WorkbookParameter 屬性:返回或設(shè)置為工作簿參數(shù)指定的Name對象。 讀/寫

          Validation對象

          代表工作表區(qū)域的數(shù)據(jù)有效性規(guī)則。

          方法

          Add方法:向指定區(qū)域添加數(shù)據(jù)驗(yàn)證。

          Delete 方法:刪除對象。

          Modify 方法:修改指定區(qū)域的數(shù)據(jù)有效性驗(yàn)證。

          屬性

          AlertStyle 屬性:返回有效性檢驗(yàn)警告樣式。 只讀的**XlDVAlertStyle**。信息圖標(biāo),警告圖標(biāo),禁止圖標(biāo)

          Application 屬性:

          在不使用對象識別符的情況下使用時, 此屬性返回代表 Microsoft Excel 應(yīng)用程序的**Application** 對象。 如果與對象識別符一起使用,則此屬性返回代表指定對象的創(chuàng)建者的 Application 對象(可以將此屬性與 OLE 自動化對象一起使用以返回該對象的應(yīng)用程序)。 只讀。

          Creator 屬性:返回一個 32 位整數(shù),該整數(shù)指示在其中創(chuàng)建了此對象的應(yīng)用程序。 只讀 Long。

          ErrorMessage 屬性:返回或設(shè)置數(shù)據(jù)有效性檢驗(yàn)錯誤消息。 讀/寫 String。

          ErrorTitle 屬性:返回或設(shè)置數(shù)據(jù)有效性錯誤對話框的標(biāo)題。 讀/寫 String。

          Formula1 屬性:返回與條件格式或者數(shù)據(jù)有效性相關(guān)聯(lián)的值或表達(dá)式。 可為常量值、字符串值、單元格引用或公式。 只讀的字符串。

          Formula2 屬性:返回與條件格式或數(shù)據(jù)有效性驗(yàn)證第二部分相關(guān)聯(lián)的值或表達(dá)式。 僅在數(shù)據(jù)驗(yàn)證條件格式**運(yùn)算符** 屬性為xlBetween或xlNotBetween時使用。 可為常量值、字符串值、單元格引用或公式。 只讀 String 類型。

          IgnoreBlank 屬性:如果指定區(qū)域內(nèi)的數(shù)據(jù)有效性檢驗(yàn)允許空值,則該值為 True。 讀/寫 Boolean。

          IMEMode 屬性:返回或設(shè)置日文輸入規(guī)則的說明。 可以是下表中列出的**XlIMEMode** 常量之一。 Long 類型,可讀寫。

          InCellDropdown 屬性:如果數(shù)據(jù)有效性顯示含有有效取值的下拉列表,則該屬性值為 True。 讀/寫 Boolean。

          InputMessage 屬性:返回或設(shè)置數(shù)據(jù)有效性檢驗(yàn)輸入信息。 讀/寫 String。

          InputTitle 屬性:返回或設(shè)置數(shù)據(jù)有效性輸入對話框的標(biāo)題。 讀/寫 String。 限制為32個字符。

          Operator 屬性:返回一個Long值, 它代表數(shù)據(jù)有效性的運(yùn)算符。

          Parent 屬性:返回指定對象的父對象。 只讀。

          ShowError 屬性:如果用戶輸入無效數(shù)據(jù)時顯示數(shù)據(jù)有效性檢查錯誤消息,則該屬性值為 True。 讀/寫 Boolean。

          ShowInput 屬性:如果用戶在數(shù)據(jù)有效性檢查區(qū)域內(nèi)選定了某一單元格時,顯示數(shù)據(jù)有效性檢查輸入消息,則該屬性值為 True。 讀/寫 Boolean。

          Type 屬性:返回一個Long值, 它包含一個**XlDVType** 常量, 該常量代表區(qū)域的數(shù)據(jù)類型驗(yàn)證。

          Value 屬性:返回一個布爾值, 該值指示是否滿足所有驗(yàn)證條件 (即, 如果該范圍包含有效數(shù)據(jù))。

          PageSetup 對象

          代表頁面設(shè)置說明。PageSetup 對象包含作為特性的所有頁面設(shè)置屬性(左邊距、下邊距、紙張大小等)。

          屬性(常用)

          AlignMarginsHeaderFooter 屬性:返回True excel 以對齊的邊距設(shè)置頁面設(shè)置選項(xiàng)中的頁眉和頁腳。 讀/寫 Boolean。

          BlackAndWhite 屬性:如果為true以黑白方式打印文檔中的元素。 讀/寫 Boolean。

          BottomMargin 屬性:返回或設(shè)置下邊距的大小, 以磅為單位。 讀/寫 Double。

          CenterFooter 屬性:居中對齊PageSetup對象中的頁腳信息。 讀/寫 String。

          CenterFooterPicture 屬性:返回一個代表頁腳的中心部分的圖片的**圖形** 對象。 用于設(shè)置圖片的屬性。

          CenterHeader 屬性:居中對齊中的PageSetup對象的頭信息。 讀/寫 String。

          CenterHeaderPicture 屬性:返回一個代表中心節(jié)標(biāo)頭的圖片的**圖形** 對象。 用于設(shè)置圖片的屬性。

          CenterHorizontally 屬性:如果在頁面的水平居中位置打印指定工作表,則該屬性值為 True。 Boolean 類型,可讀寫。

          CenterVertically 屬性:True如果在上的垂直居中位置打印工作表。 讀/寫 Boolean。

          DifferentFirstPageHeaderFooter 屬性 :True,如此 如果不同的頁眉或頁腳使用第一頁上。 讀/寫 Boolean。

          Draft 屬性:如果為true將圖形不打印工作表。 讀/寫 Boolean。

          EvenPage 屬性:返回或設(shè)置工作簿或節(jié)的偶數(shù)頁上的文本對齊方式。

          FirstPage 屬性:返回或設(shè)置工作簿或節(jié)的第一頁上的文本對齊方式。

          FirstPageNumber 屬性:返回或設(shè)置打印指定工作表時第一頁的頁號。 如果xlAutomatic, Microsoft Excel 將選擇第一個頁碼。 默認(rèn)值為 xlAutomatic。 Long 類型,可讀寫。

          FitToPagesTall 屬性:返回或設(shè)置打印工作表時,對工作表進(jìn)行縮放使用的頁高。 僅應(yīng)用于工作表。 讀/寫 Variant。

          FitToPagesWide 屬性:返回或設(shè)置打印工作表時,對工作表進(jìn)行縮放使用的頁寬。 僅應(yīng)用于工作表。 讀/寫 Variant。

          FooterMargin 屬性:返回或設(shè)置從頁面底部的距離,頁腳,以磅為單位。 讀/寫 Double。

          HeaderMargin 屬性:返回或設(shè)置從頁面頂部的距離,頁眉,以磅為單位。 讀/寫 Double。

          LeftFooter 屬性:返回或設(shè)置工作簿或節(jié)的左頁腳上的文本對齊方式。

          LeftFooterPicture 屬性:返回一個代表左側(cè)的頁腳節(jié)的圖片的**圖形** 對象。 用于設(shè)置圖片的屬性。

          LeftHeader 屬性:返回或設(shè)置工作簿或節(jié)的左頁眉上的文本對齊方式。

          LeftHeaderPicture 屬性:返回一個代表左側(cè)標(biāo)頭的各個部分的圖片的**圖形** 對象。 用于設(shè)置圖片的屬性。

          LeftMargin 屬性:以磅為單位返回或設(shè)置左邊距的大小。 讀/寫Doub

          OddAndEvenPagesHeaderFooter 屬性 :True 指定的 PageSetup 對象是否的奇數(shù)和偶數(shù)頁不同的頁眉和頁腳。 讀/寫 Boolean。

          Order屬性:返回或設(shè)置一個**XlOrder** 值, 該值代表 Microsoft Excel 在打印大型工作表時對頁面編號時使用的順序。

          Orientation屬性:返回或設(shè)置一個**XlPageOrientation** 值, 它代表縱向或橫向打印模式。

          Pages屬性:返回或設(shè)置pages集合中頁面的計數(shù)或項(xiàng)目號。

          PaperSize 屬性:返回或設(shè)置紙張大小。 XlPaperSize 類型,可讀寫。

          PrintArea 屬性:使用采用宏語言的 A1 樣式引用,以字符串形式返回或設(shè)置要打印的區(qū)域。 讀/寫 String。

          PrintComments 屬性:返回或設(shè)置批注隨工作表打印的方式。 讀/寫**XlPrintLocation**。

          PrintErrors 屬性:設(shè)置或返回一個**XlPrintErrors** 常量, 該常量指定顯示的打印錯誤的類型。 該功能允許用戶在打印工作表時取消錯誤顯示。 可讀寫。

          PrintGridlines 屬性:True如果在上打印單元格網(wǎng)格線。 僅適用于工作表。 讀/寫 Boolean。

          PrintHeadings 屬性:如果為true行和列標(biāo)題的打印此頁。 僅適用于工作表。 讀/寫 Boolean。

          PrintNotes 屬性:True如果單元格注釋打印作為表的尾注。 僅適用于工作表。 讀/寫 Boolean。

          PrintQuality 屬性:返回或設(shè)置打印質(zhì)量。 讀/寫 Variant。

          PrintTitleColumns 屬性:返回或設(shè)置包含要重復(fù)左側(cè)的每一頁中,在語言的宏的 A1 樣式表示法字符串形式的單元格的列。 讀/寫 String。

          PrintTitleRows 屬性:返回或設(shè)置那些包含在每一頁頂部重復(fù)出現(xiàn)的單元格的行,用宏語言字符串以 A1 樣式表示法表示。 讀/寫 String。

          RightFooter 屬性:返回或設(shè)置頁的右邊緣和頁腳的右邊界之間的距離 (以磅為單位)。 讀/寫 String。

          RightFooterPicture 屬性:返回一個代表頁腳的右部分的圖片的**圖形** 對象。 用于設(shè)置圖片的屬性。

          PageSetup.RightHeader 屬性:返回或設(shè)置頁眉的右側(cè)部分。 讀/寫 String。

          RightHeaderPicture 屬性:指定應(yīng)在右側(cè)的標(biāo)頭中顯示的圖形圖像。 只讀。

          RightMargin 屬性:返回或設(shè)置的右邊距的大小,以磅為單位。 讀/寫 Double。

          ScaleWithDocHeaderFooter 屬性:返回或設(shè)置如果文檔的大小更改時應(yīng)與文檔擴(kuò)展的頁眉和頁腳。 讀/寫 Boolean。

          TopMargin 屬性:返回或設(shè)置上邊距的大小,以磅為單位。 讀/寫 Double。

          Zoom屬性:返回或設(shè)置一個Variant值, 它代表 Microsoft Excel 用于縮放工作表時使用的百分比 (10% 到 400%)。

          Hyperlinks 對象

          代表工作表或區(qū)域的超鏈接的集合。

          方法

          add方法:向指定的區(qū)域或形狀添加超鏈接。

          Delete 方法:刪除對象。

          屬性

          Application 屬性:在不使用對象識別符的情況下使用時, 此屬性返回代表 Microsoft Excel 應(yīng)用程序的**Application** 對象。 如果與對象識別符一起使用,則此屬性返回代表指定對象的創(chuàng)建者的 Application 對象(可以將此屬性與 OLE 自動化對象一起使用以返回該對象的應(yīng)用程序)。 只讀。

          Count 屬性:返回一個 Long 值,它表示集合中對象的數(shù)量。

          Creator 屬性:返回一個 32 位整數(shù),該整數(shù)指示在其中創(chuàng)建了此對象的應(yīng)用程序。 只讀 Long。

          Item 屬性:從集合中返回一個對象。

          Parent 屬性:返回指定對象的父對象。 只讀。

          Hyperlink 對象

          代表一個超鏈接。

          方法

          AddToFavorites 方法:將工作簿或超鏈接的快捷方式添加到“收藏夾”文件夾。

          CreateNewDocument 方法:新建一篇鏈接到指定超鏈接的文檔。

          Delete 方法:刪除對象。

          Follow方法:顯示緩存文檔 (如果已下載)。 否則,此方法將解析該超鏈接,下載目標(biāo)文檔,并在相應(yīng)的應(yīng)用程序中顯示此文檔。

          屬性

          Address 屬性:返回或設(shè)置一個String值,該值代表目標(biāo)文檔的地址。

          Application 屬性:在不使用對象識別符的情況下使用時, 此屬性返回代表 Microsoft Excel 應(yīng)用程序的**Application** 對象。 如果與對象識別符一起使用,則此屬性返回代表指定對象的創(chuàng)建者的 Application 對象(可以將此屬性與 OLE 自動化對象一起使用以返回該對象的應(yīng)用程序)。 只讀。

          Creator屬性:返回一個 32 位整數(shù),該整數(shù)指示在其中創(chuàng)建了此對象的應(yīng)用程序。 只讀 Long。

          EmailSubject 屬性:返回或設(shè)置指定超鏈接的電子郵件主題行的文本字符串。 主題行追加到超鏈接的地址。 讀/寫 String。

          Name 屬性:返回一個String值,它代表對象的名稱。

          Parent 屬性:返回指定對象的父對象。 只讀。

          Range 屬性:返回一個**range** 對象, 該對象代表指定的超鏈接所附加到的區(qū)域。

          ScreenTip屬性:返回或設(shè)置指定超鏈接的屏幕提示文字。 讀/寫 String。

          Shape 屬性:返回一個**Shape** 對象,它代表附加到指定的超鏈接的形狀。

          SubAddress 屬性:返回或設(shè)置與超鏈接相關(guān)聯(lián)的文檔中的位置。 讀/寫 String。

          TextToDisplay 屬性:返回或設(shè)置指定超鏈接顯示的文本。 默認(rèn)值是超鏈接的地址。 讀/寫 String。

          Type屬性:返回一個Long值, 它包含一個**MsoHyperlinkType** 常量, 該常量代表 HTML 框架的位置。

          Filter篩選器對象

          代表單個列的篩選。Filter對象是 Filters 集合中的成員。 Filters 集合包含自動篩選區(qū)域中的所有篩選。

          屬性

          Application 屬性:在不使用對象識別符的情況下使用時, 此屬性返回代表 Microsoft Excel 應(yīng)用程序的**Application** 對象。 如果與對象識別符一起使用,則此屬性返回代表指定對象的創(chuàng)建者的 Application 對象(可以將此屬性與 OLE 自動化對象一起使用以返回該對象的應(yīng)用程序)。 只讀。

          Count屬性:返回集合中對象的數(shù)目。 只讀 Long。

          Creator 屬性:返回一個 32 位整數(shù),該整數(shù)指示在其中創(chuàng)建了此對象的應(yīng)用程序。 只讀 Long。

          Criteria1 屬性:篩選區(qū)域中返回指定列的第一個篩選的值。 只讀的Variant。

          Criteria2 屬性:篩選區(qū)域中返回指定列的第二個篩選的值。 只讀的Variant。

          On 屬性:True如果位于指定的篩選器。 只讀 Boolean。

          Operator屬性:返回一個**XlAutoFilterOperator** 值, 該值代表關(guān)聯(lián)指定篩選器所應(yīng)用的兩個條件的運(yùn)算符。

          Parent 屬性:返回指定對象的父對象。 只讀。

          Filters 對象

          Filter 對象的集合, 該集合代表自動篩選區(qū)域中的所有篩選器。

          AutoFilter 對象

          代表對指定工作表的自動篩選。

          方法

          ApplyFilter 方法:應(yīng)用指定的自動篩選對象。

          ShowAllData 方法:顯示自動篩選對象返回的所有數(shù)據(jù)。

          屬性(常用)

          FilterMode 屬性:如果工作表處于自動篩選模式, 則返回True 。 只讀 Boolean 類型。

          Filters 屬性:返回一個**Filters** 集合, 該集合代表自動篩選區(qū)域中的所有篩選器。 此為只讀屬性。

          Range屬性:返回一個**range** 對象, 該對象代表應(yīng)用指定的自動篩選的區(qū)域。

          Sort屬性:獲取一個或多個列, 并對AutoFilter集合的排序順序進(jìn)行排序。

          相關(guān)代碼說明和實(shí)例可查詢VBA開發(fā)文檔 以上內(nèi)容是本人自學(xué)筆記總結(jié),歡迎指正,有關(guān)Excel的問題,可私信聯(lián)系,互相交流討論,共同進(jìn)步,謝謝。

          目/技術(shù)

          一、跨域

          1、同源策略

          瀏覽器同源策略限制請求

          同源是指"協(xié)議+域名+端口"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。

          限制以下行為

          1. Cookie、LocalStorage 和 IndexDB 無法讀取
          2. DOM 和 Js對象無法獲得
          3. AJAX 請求不能發(fā)送

          有三個標(biāo)簽是允許跨域加載資源

          • <img src=XXX>
          • <link href=XXX>
          • <script src=XXX>

          2、解決方案

          1)通過jsonp跨域

          script標(biāo)簽不受策略影響,可以動態(tài)生成script去請求數(shù)據(jù),但是僅限Get請求

          原生實(shí)現(xiàn)

          <script>
            var script = document.createElement('script');
            script.type = 'text/javascript';   
            // 傳參并指定回調(diào)執(zhí)行函數(shù)為onBack
            script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';    
            document.head.appendChild(script);    
            // 回調(diào)執(zhí)行函數(shù)
            function onBack(res) {
              alert(JSON.stringify(res));
            } 
          </script>
          

          vue實(shí)現(xiàn)

          this.$http.jsonp(
            'http://www.domain2.com:8080/login', 
             {    
               params: {},    
              jsonp: 'onBack'
             }
            ).then(res => { console.log(res); }
          )
          

          2)document.domain + iframe跨域

          僅限主域相同,子域不同的跨域應(yīng)用場景

          實(shí)現(xiàn)原理:兩個頁面都通過js強(qiáng)制設(shè)置document.domain為基礎(chǔ)主域,就實(shí)現(xiàn)了同域

          <!-- 父窗口:http://www.domain.com/a.html -->
          <iframe id="iframe" src="http://child.domain.com/b.html">
          </iframe>
          
          <script>
            document.domain = 'domain.com';    
            var user = 'admin';
          </script>
          
          <!-- 子窗口:http://child.domain.com/b.html -->
          <script>
            document.domain = 'domain.com';    
            // 獲取父窗口中變量
            alert('get js data from parent ---> '+ window.parent.user);
          </script>
          

          3)location.hash + iframe

          實(shí)現(xiàn)原理: a欲與b跨域相互通信,通過中間頁c來實(shí)現(xiàn)。 三個頁面,不同域之間利用iframe的location.hash傳值,相同域之間直接js訪問來通信。

          具體實(shí)現(xiàn): A域:a.html -> B域:b.html -> A域:c.html,

          a與b不同域只能通過hash值單向通信,b與c也不同域也只能單向通信,但c與a同域,所以c可通過parent.parent訪問a頁面所有對象。

          4)window.name + iframe跨域

          window.name屬性的獨(dú)特之處:name值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的 name 值(2MB)。

          通過iframe的src屬性由外域轉(zhuǎn)向本地域,跨域數(shù)據(jù)即由iframe的window.name從外域傳遞到本地域。這個就巧妙地繞過了瀏覽器的跨域訪問限制,但同時它又是安全操作。

          5) postMessage跨域

          postMessage一般用于解決以下問題

          a.) 頁面和其打開的新窗口的數(shù)據(jù)傳遞

          b.) 多窗口之間消息傳遞

          c.) 頁面與嵌套的iframe消息傳遞

          d.) 上面三個場景的跨域數(shù)據(jù)傳遞

          <!-- a頁面:http://www.domain1.com/a.html -->
          <iframe id="iframe" 
                  src="http://www.domain2.com/b.html" 
                  style="display:none;">
          </iframe>
          <script>       
            var iframe = document.getElementById('iframe');
            iframe.onload = function() {        
              var data = {           
                name: 'aym'
              };        
              // 向domain2傳送跨域數(shù)據(jù)
              iframe.contentWindow.postMessage
              (JSON.stringify(data),
               'http://www.domain2.com');
            };    
            // 接受domain2返回數(shù)據(jù)
            window.addEventListener
            ('message', function(e) {
              alert('data from domain2 ---> ' + e.data);
            }, 
             false);
          </script>
          
          <!-- b頁面:http://www.domain2.com/b.html -->
          <script>
            // 接收domain1的數(shù)據(jù)
            window.addEventListener
            ('message', function(e) {
              alert('data from domain1 ---> ' + e.data);        
              var data = JSON.parse(e.data);        
              if (data) {
                data.number = 16;            
                // 處理后再發(fā)回domain1
                window.parent.postMessage(JSON.stringify(data),
                                          'http://www.domain1.com');
              }
            }, false);
          </script>
          

          6)跨域資源共享(CORS):主流的跨域解決方案

          服務(wù)端設(shè)置Access-Control-Allow-Origin即可

          若要帶cookie請求:前后端都需要設(shè)置。

          前端: : 檢查前端設(shè)置是否帶cookie:xhr.withCredentials = true;

          通過這種方式解決跨域問題的話,會在發(fā)送請求時出現(xiàn)兩種情況,分別為簡單請求復(fù)雜請求

          簡單請求:

          使用下列方法之一:

          • GET
          • HEAD
          • POST

          Content-Type 的值僅限于下列三者之一:

          • text/plain
          • multipart/form-data
          • application/x-www-form-urlencoded

          不符合以上條件的請求就肯定是復(fù)雜請求了。 復(fù)雜請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預(yù)檢"請求, 該請求是 option 方法的,通過該請求來知道服務(wù)端是否允許跨域請求。

          OPTIONS預(yù)檢請求

          請求頭:

          • Origin:當(dāng)前請求源,和響應(yīng)頭里的Access-Control-Allow-Origin 對標(biāo), 是否允許當(dāng)前源訪問,Origin是不可修改的
          • Access-Control-Request-Headers:本次真實(shí)請求的額外請求頭,和響應(yīng)頭里的Access-Control-Allow-Headers對標(biāo),是否允許真實(shí)請求的請求頭
          • Access-Control-Request-Method:本次真實(shí)請求的額外方法,和響應(yīng)頭里的Access-Control-Allow-Methods對標(biāo),是否允許真實(shí)請求使用的請求方法

          響應(yīng)頭

          • Access-Control-Allow-Credentials:
          • 這里的Credentials(憑證)其意包括:Cookie ,授權(quán)標(biāo)頭或 TLS 客戶端證書,默認(rèn)CORS請求是不帶Cookies的,這與JSONP不同,JSONP每次請求都攜帶Cookies的,當(dāng)然跨域允許帶Cookies會導(dǎo)致CSRF漏洞。如果非要跨域傳遞Cookies,web端需要給ajax設(shè)置withCredentials為true,同時,服務(wù)器也必須使用Access-Control-Allow-Credentials頭響應(yīng)。此響應(yīng)頭true意味著服務(wù)器允許cookies(或其他用戶憑據(jù))包含在跨域請求中。另外,簡單的GET請求是不預(yù)檢的,即使請求的時候設(shè)置widthCrenditials為true,如果響應(yīng)頭不帶Access-Control-Allow-Credentials,則會導(dǎo)致整個響應(yīng)資源被瀏覽器忽略。
          • Access-Control-Allow-Headers
          • Access-Control-Allow-Methods
          • Access-Control-Allow-Origin
          • Access-Control-Expose-Headers:
          • 在CORS中,默認(rèn)的,只允許客戶端讀取下面六個響應(yīng)頭(在axios響應(yīng)對象的headers里能看到):
            • Cache-Control
            • Content-Language
            • Content-Type
            • Expires
            • Last-Modified
            • Pragma

          如果這六個以外的響應(yīng)頭要是想讓客戶端讀取到,就需要設(shè)置Access-Control-Expose-Headers這個為響應(yīng)頭名了,比如Access-Control-Expose-Headers: Token

          • Access-Control-Max-Age:設(shè)置預(yù)檢請求的有效時長,就是服務(wù)器允許的請求方法和請求頭做個緩存。

          7)nginx代理跨域

          nginx配置解決iconfont跨域

          瀏覽器跨域訪問js、css、img等常規(guī)靜態(tài)資源被同源策略許可,但iconfont字體文件(eot|otf|ttf|woff|svg)例外,此時可在nginx的靜態(tài)資源服務(wù)器中加入以下配置。

          location / {
            add_header 
            Access-Control-Allow-Origin *;
          }
          

          反向代理

          跨域原理: 同源策略是瀏覽器的安全策略,不是HTTP協(xié)議的一部分。服務(wù)器端調(diào)用HTTP接口只是使用HTTP協(xié)議,不會執(zhí)行JS腳本,不需要同源策略,也就不存在跨越問題。

          通過nginx配置一個代理服務(wù)器(域名與domain1相同,端口不同)做跳板機(jī),反向代理訪問domain2接口,并且可以順便修改cookie中domain信息,方便當(dāng)前域cookie寫入,實(shí)現(xiàn)跨域登錄。

          #proxy服務(wù)器
          server {   
            listen      
            81;    
            server_name  www.domain1.com;    
            location / {        
              proxy_pass
                http://www.domain2.com:8080;  
              #反向代理
              proxy_cookie_domain 
              www.domain2.com www.domain1.com;
              # 修改cookie里域名
              index  index.html index.htm;       
              # 用webpack-dev-server等中間件代理接口訪問nignx時,
              # 此時無瀏覽器參與,故沒有同源限制,面的跨域配置可不啟用
              add_header Access-Control-Allow-Origin 
              http://www.domain1.com;  
              # 當(dāng)前端只跨域不帶cookie時,可為*
              add_header Access-Control-Allow-Credentials true;
            }
          }
          

          8)nodejs中間件代理跨域

          node中間件實(shí)現(xiàn)跨域代理,原理大致與nginx相同,都是通過啟一個代理服務(wù)器,實(shí)現(xiàn)數(shù)據(jù)的轉(zhuǎn)發(fā),也可以通過設(shè)置cookieDomainRewrite參數(shù)修改響應(yīng)頭中cookie中域名,實(shí)現(xiàn)當(dāng)前域的cookie寫入,方便接口登錄認(rèn)證。

          9)WebSocket協(xié)議跨域

          WebSocket protocol是HTML5一種新的協(xié)議。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信,同時允許跨域通訊,是server push技術(shù)的一種很好的實(shí)現(xiàn)。

          原生WebSocket API使用起來不太方便,我們使用Socket.io,它很好地封裝了webSocket接口,提供了更簡單、靈活的接口,也對不支持webSocket的瀏覽器提供了向下兼容。

          <div>user input:
            <input type="text">
          </div>
          
          <script src="./socket.io.js"></script>
          <script>var socket = io('
                                  http://www.domain2.com:8080');
                                  // 連接成功處理
                                  socket.on('connect', function() {    
              // 監(jiān)聽服務(wù)端消息
              socket.on('message', function(msg) {        
                console.log('data from server: ---> ' + msg); 
              });   
              // 監(jiān)聽服務(wù)端關(guān)閉
              socket.on('disconnect', function() { 
                console.log('Server socket has closed.'); 
              });
            });
            document.getElementsByTagName('input')
            [0].onblur = function() {
              socket.send(this.value);
            };
           </script>
          

          二、 輪播圖實(shí)現(xiàn)

          1、借助組件或者框架:Swiper、BootStrap

          實(shí)現(xiàn)原理:參考代碼

          2、css3動畫實(shí)現(xiàn)的輪播圖

          實(shí)現(xiàn)原理:

          1. 設(shè)置大的div
          2. a) 設(shè)置絕對定位,定位位置,
          3. b) 設(shè)置圖片展示出來的高度和寬度(height和width);
          4. c) 設(shè)置overflow:hidden;設(shè)置超出部分隱藏;使得圖片只能在這個框中顯示;
          5. 設(shè)置小的div,將所有圖片都包起來;寬度是所有圖片的寬度;設(shè)置position:relative / position:absolute 來讓它可以實(shí)現(xiàn)輪播的功能;必不可少。(自己的理解,設(shè)置大div和小div 的position,來讓div浮起來,脫離文檔流,就像云一樣,可以飄了~)
          6. 給里面的圖片設(shè)置float:left;向左浮動,可以讓所有圖片都在同一行;如果沒有float:left;會導(dǎo)致圖片輪播的時候出現(xiàn)空白;
          7. 加入動畫;每次都向左偏移一個圖片的寬度,即可實(shí)現(xiàn)圖片輪播;
          8. 將第一張圖片與最后一張圖片設(shè)置成一樣的,是為了實(shí)現(xiàn)視覺上的無縫連接;

          3、JS方法

          輪播圖原理就是圖片的移動。所有輪播圖片橫向排列,在一個窗口中顯示一張圖片,窗口外的圖片隱藏,每一次一排圖片就是移動一張圖片的距離,切換到下一張圖片,即可實(shí)現(xiàn)圖片輪播。

          圖片的移動有兩種方式:

          • translate 實(shí)現(xiàn)的圖片移動
          • position定位實(shí)現(xiàn)圖片的偏移

          圖片的自動播放,使用間隔定時器 setInterval

          通過定位的方式,改變left或top的值,形成輪播圖的效果

          1、自動輪播:

          用setInterval(func,time);

          被調(diào)用的函數(shù)不斷地自加,也就是不斷地往后循環(huán),當(dāng)圖片到最后一張時,讓其跳轉(zhuǎn)到第一張。

          先將所有圖片,下方指示點(diǎn)的樣式設(shè)置為一樣的,再對當(dāng)前索引對應(yīng)的圖片,設(shè)置特別的樣式。

          2. 鼠標(biāo)移入,移出事件

          注意:

          1)如果你想要通過點(diǎn)擊事件來改變圖片的移動時,就必須讓鼠標(biāo)移動到上面時設(shè)置清除計時器;因?yàn)槿绻辉O(shè)置的話,當(dāng)你通過點(diǎn)擊事件改變它時,它自身也會自己改變,會出現(xiàn)混亂。

          2)當(dāng)清除完后,鼠標(biāo)移出后需要重新啟動計時器,這時候不能再給它設(shè)置var jishi;因?yàn)槿绻偌由蟰ar 的話,相當(dāng)于重新又定義了一個變量,會有好幾個計時器同時進(jìn)行,會越來越快。

          3. 手動輪播 底下指示點(diǎn)的按鈕控制

          判斷點(diǎn)擊的是哪個點(diǎn),然后將它的索引值賦值給index,再通過調(diào)用change功能,實(shí)現(xiàn)它的改變。

          4. 左右按鈕的控制

          讓它實(shí)現(xiàn)自增或自減,然后調(diào)用change功能來改變樣式。 其實(shí)這里的知識點(diǎn)和自動輪播里的知識點(diǎn)差不多。(從最后一張圖片跳轉(zhuǎn)到第一張圖片 ,從第一張?zhí)D(zhuǎn)到最后一張。)

          無論是自動輪播,還是點(diǎn)擊控制,都要加入change功能以及index 來實(shí)現(xiàn)對樣式的控制,從而實(shí)現(xiàn)輪播的效果。

          三、圖片懶加載

          原理

          優(yōu)先加載可視區(qū)域的內(nèi)容,其他部分等進(jìn)入了可視區(qū)域再加載,從而提高性能

          原理:

          一張圖片就是一個<img>標(biāo)簽,瀏覽器是否發(fā)起請求圖片是根據(jù)<img>的src屬性,所以實(shí)現(xiàn)懶加載的關(guān)鍵就是,在圖片沒有進(jìn)入可視區(qū)域時,先不給<img>的src賦值,這樣瀏覽器就不會發(fā)送請求了,等到圖片進(jìn)入可視區(qū)域再給src賦值。

          實(shí)現(xiàn)思路:

          1. 加載loading圖片
          2. 判斷哪些圖片要加載【重點(diǎn)】
          3. 當(dāng)圖片距離頂部的距離top-height等于可視區(qū)域h和滾動區(qū)域高度s之和時說明圖片馬上就要進(jìn)入可視區(qū)了
          4. 隱形加載圖片
          5. 創(chuàng)建一個臨時圖片,new Image() ,不會加載到頁面上去,實(shí)現(xiàn)隱形加載
          6. 替換真圖片
          7. 替換src屬性

          頁面布局位置基礎(chǔ)知識

          網(wǎng)頁可見區(qū)域?qū)挘?document.body.clientWidth; 網(wǎng)頁可見區(qū)域高: document.body.clientHeight; 網(wǎng)頁可見區(qū)域?qū)挘?document.body.offsetWidth (包括邊線的寬); 網(wǎng)頁可見區(qū)域高: document.body.offsetHeight (包括邊線的高);

          網(wǎng)頁正文全文寬: document.body.scrollWidth; 網(wǎng)頁正文全文高: document.body.scrollHeight; 網(wǎng)頁被卷去的高: document.body.scrollTop; 網(wǎng)頁被卷去的左: document.body.scrollLeft;

          網(wǎng)頁正文部分上: window.screenTop; 網(wǎng)頁正文部分左: window.screenLeft; 屏幕分辨率的高: window.screen.height; 屏幕分辨率的寬: window.screen.width; 屏幕可用工作區(qū)高度: window.screen.availHeight;

          • 對塊級元素來說,offsetTop、offsetLeft、offsetWidth 及 offsetHeight 描述了元素相對于 offsetParent 的邊界框
          • HTMLElement.offsetParent 是一個只讀屬性,返回一個指向最近的(指包含層級上的最近)包含該元素的定位元素或者最近的 table,td,th,body元素。當(dāng)元素的 style.display 設(shè)置為 "none" 時,offsetParent 返回 null。offsetParent 很有用,因?yàn)?offsetTop 和 offsetLeft 都是相對于其內(nèi)邊距邊界的。
          • HTMLElement.offsetTop 為只讀屬性,它返回當(dāng)前元素相對于其 offsetParent 元素的頂部的距離。
          • window.innerHeight:瀏覽器窗口的視口(viewport)高度(以像素為單位);如果有水平滾動條,也包括滾動條高度。

          代碼實(shí)現(xiàn)

          可以給img標(biāo)簽統(tǒng)一自定義屬性data-src='default.png',當(dāng)檢測到圖片出現(xiàn)在窗口之后再補(bǔ)充src屬性,此時才會進(jìn)行圖片資源加載。

          function lazyload() {
            const imgs = document.getElementsByTagName('img');
            const len = imgs.length;
            // 視口的高度
            const viewHeight = document.documentElement.clientHeight;
            // 滾動條高度
            const scrollHeight = document.documentElement.scrollTop || document.body.scrollTop;
            for (let i = 0; i < len; i++) {
              const offsetHeight = imgs[i].offsetTop;
              if (offsetHeight < viewHeight + scrollHeight) {
                const src = imgs[i].dataset.src;
                imgs[i].src = src;
              }
            }
          }
          
          // 可以使用節(jié)流優(yōu)化一下
          window.addEventListener('scroll', lazyload);
          

          四、單點(diǎn)登錄(SSO)實(shí)現(xiàn)

          1. 說明

          單點(diǎn)登錄(Single Sign On),簡稱為 SSO,是目前比較流行的企業(yè)業(yè)務(wù)整合的解決方案之一

          SSO的定義是在多個應(yīng)用系統(tǒng)中,用戶只需要登錄一次就可以訪問所有相互信任的應(yīng)用系統(tǒng)

          SSO 一般都需要一個獨(dú)立的認(rèn)證中心(passport),子系統(tǒng)的登錄均得通過passport,子系統(tǒng)本身將不參與登錄操作

          當(dāng)一個系統(tǒng)成功登錄以后,passport將會頒發(fā)一個令牌給各個子系統(tǒng),子系統(tǒng)可以拿著令牌會獲取各自的受保護(hù)資源,為了減少頻繁認(rèn)證,各個子系統(tǒng)在被passport授權(quán)以后,會建立一個局部會話,在一定時間內(nèi)可以無需再次向passport發(fā)起認(rèn)證

          2. 同域名下的單點(diǎn)登錄

          cookie的domain屬性設(shè)置為當(dāng)前域的父域,并且父域的cookie會被子域所共享。path屬性默認(rèn)為web應(yīng)用的上下文路徑

          利用 Cookie 的這個特點(diǎn),我們只需要將Cookie的domain屬性設(shè)置為父域的域名(主域名),同時將 Cookie的path屬性設(shè)置為根路徑,將 Session ID(或 Token)保存到父域中。這樣所有的子域應(yīng)用就都可以訪問到這個Cookie

          不過這要求應(yīng)用系統(tǒng)的域名需建立在一個共同的主域名之下,如tieba.baidu.com 和 map.baidu.com,它們都建立在 baidu.com這個主域名之下,那么它們就可以通過這種方式來實(shí)現(xiàn)單點(diǎn)登錄

          3. 不同域名下的單點(diǎn)登錄

          這里只介紹使用過的:CASCentral Authentication Service) 官網(wǎng)流程圖:

          app1登錄

          1. 用戶訪問app1系統(tǒng),app1系統(tǒng)是需要登錄的,但用戶現(xiàn)在沒有登錄。重定向到sso認(rèn)證中心,并將自己的地址作為參數(shù)。
          2. www.sso.com?service=www.java3y.com (www.java3y.com視為app系統(tǒng)的地址)
          3. 跳轉(zhuǎn)到CAS server,即SSO登錄系統(tǒng),以后圖中的CAS Server我們統(tǒng)一叫做SSO系統(tǒng)。 SSO系統(tǒng)也沒有登錄,彈出用戶登錄頁。
          4. 用戶填寫用戶名、密碼,SSO系統(tǒng)進(jìn)行認(rèn)證后,將登錄狀態(tài)寫入SSO的session,瀏覽器(Browser)中寫入SSO域下的Cookie
          5. 即:用戶與認(rèn)證中心建立全局會話(生成一份Token,寫到Cookie中,保存在瀏覽器上)
          6. 認(rèn)證中心重定向回app系統(tǒng),并把Token攜帶過去給app1,重定向的地址如:
          7. www.java3y.com?token=xxxxxxx
          8. SSO系統(tǒng)登錄完成后會生成一個ST(Service Ticket) ,然后跳轉(zhuǎn)到app1系統(tǒng),同時將ST作為參數(shù)傳遞給app1系統(tǒng)。
          9. app1系統(tǒng)拿到ST后,從后臺向SSO發(fā)送請求,驗(yàn)證ST是否有效
          10. 驗(yàn)證通過后,app1系統(tǒng)將登錄狀態(tài)寫入session并設(shè)置app域下的Cookie。注意,此處的 cookie 和 session 保存的是用戶在 app1 系統(tǒng)的登錄狀態(tài),和 CAS 無關(guān)。

          app2登錄時:

          1. 用戶訪問app2系統(tǒng),app2系統(tǒng)沒有登錄,跳轉(zhuǎn)到SSO。
          2. 由于SSO已經(jīng)登錄了,不需要重新登錄認(rèn)證。
          3. SSO生成ST,瀏覽器跳轉(zhuǎn)到app2系統(tǒng),并將ST作為參數(shù)傳遞給app2。
          4. app2拿到ST,后臺訪問SSO,驗(yàn)證ST是否有效。
          5. 驗(yàn)證成功后,app2將登錄狀態(tài)寫入session,并在app2域下寫入Cookie。

          五、前端水印

          1. 顯性水印+DOM元素直接遮蓋: 將水印文字直接通過一層DOM元素,覆蓋到需要添加水印的圖片上
          2. 顯性水印+Canvas
          3. 算法和顯性水印+DOM元素直接遮蓋一樣,但其性能優(yōu)于方案一,安全性略高于方案一 直接通過Canvas繪畫,避免了在水印密度較大的情況下大量DOM元素的創(chuàng)建與添加 并且Canvas在部分環(huán)境與瀏覽器下?lián)碛肎PU加速的功能,故而性能提升較大
          4. 保護(hù)程序+DOM元素直接遮蓋
          5. 上述方案中,將資源繪制在Canvas雖是一種可行方案,但對于普通的DOM元素(非圖片) 雖然有可行方案例如html2canva來將DOM轉(zhuǎn)化為·Canvas,但是實(shí)現(xiàn)過于繁雜 并且DOM將失去其事件處理響應(yīng)功能,故而并不推薦這么使用,除非需要保護(hù)的資源沒有任何交互 使用瀏覽器新增的MutationObserver特性(主流瀏覽器都已支持,參考資料中有具體文檔鏈接) 用來監(jiān)視需要保護(hù)的DOM元素及其子代的更改(包括監(jiān)視DOM及其子代的刪減、Style的變化,標(biāo)簽屬性變化等等),一旦回調(diào)函數(shù)通知出現(xiàn)了任何更改 我們可以做出提示,提醒用戶操作違法,并且刪除掉水印,并且重新生成水印DOM 或者在用戶更改了水印DOM的時候,將需要顯示的保護(hù)資源DOM一并刪除
          6. Base64傳輸 將資源文件通過Base64編碼并且通過request請求返回(或是直接后端保存Base64) 而對于Img來說,Base64只需要一些小小的的處理就可以在Web中使用(Base64字符串可以直接作為img的url,但建議使用Js Image對象,這樣避免了暴露原始URL到HTML中
          7. 加料的Base64

          六、大文件斷點(diǎn)續(xù)傳

          上傳大文件時,以下幾個變量會影響我們的用戶體驗(yàn)

          • 服務(wù)器處理數(shù)據(jù)的能力
          • 請求超時
          • 網(wǎng)絡(luò)波動

          分片上傳:

          分片上傳,就是將所要上傳的文件,按照一定的大小,將整個文件分隔成多個數(shù)據(jù)塊(Part)來進(jìn)行分片上傳,上傳完之后再由服務(wù)端對所有上傳的文件進(jìn)行匯總整合成原始的文件

          大致流程如下:

          1. 將需要上傳的文件按照一定的分割規(guī)則,分割成相同大小的數(shù)據(jù)塊;
          2. 初始化一個分片上傳任務(wù),返回本次分片上傳唯一標(biāo)識;
          3. 按照一定的策略(串行或并行)發(fā)送各個分片數(shù)據(jù)塊;
          4. 發(fā)送完成后,服務(wù)端根據(jù)判斷數(shù)據(jù)上傳是否完整,如果完整,則進(jìn)行數(shù)據(jù)塊合成得到原始文件

          斷點(diǎn)續(xù)傳:

          斷點(diǎn)續(xù)傳指的是在下載或上傳時,將下載或上傳任務(wù)人為的劃分為幾個部分

          每一個部分采用一個線程進(jìn)行上傳或下載,如果碰到網(wǎng)絡(luò)故障,可以從已經(jīng)上傳或下載的部分開始繼續(xù)上傳下載未完成的部分,而沒有必要從頭開始上傳下載。用戶可以節(jié)省時間,提高速度

          一般實(shí)現(xiàn)方式有兩種:

          • 服務(wù)器端返回,告知從哪開始
          • 瀏覽器端自行處理

          上傳過程中將文件在服務(wù)器寫為臨時文件,等全部寫完了(文件上傳完),將此臨時文件重命名為正式文件即可

          如果中途上傳中斷過,下次上傳的時候根據(jù)當(dāng)前臨時文件大小,作為在客戶端讀取文件的偏移量,從此位置繼續(xù)讀取文件數(shù)據(jù)塊,上傳到服務(wù)器從此偏移量繼續(xù)寫入文件即可

          實(shí)現(xiàn)思路:

          整體思路比較簡單,拿到文件,保存文件唯一性標(biāo)識,切割文件,分段上傳,每次上傳一段,根據(jù)唯一性標(biāo)識判斷文件上傳進(jìn)度,直到文件的全部片段上傳完畢

          七、掃描二維碼登錄的原理

          1)移動端基于 token 的認(rèn)證機(jī)制

          基于 token 的認(rèn)證機(jī)制,只有在第一次使用需要輸入賬號密碼,后續(xù)使用將不在輸入賬號密碼。 其實(shí)在登陸的時候不僅傳入賬號、密碼,還傳入了手機(jī)的設(shè)備信息

          在服務(wù)端驗(yàn)證賬號、密碼正確后,服務(wù)端會做兩件事。

          1. 將賬號與設(shè)備關(guān)聯(lián)起來,在某種意義上,設(shè)備信息就代表著賬號。
          2. 生成一個 token 令牌,并且在 token 與賬號、設(shè)備關(guān)聯(lián),類似于key/value,token作為 key,賬號、設(shè)備信息作為value,持久化在磁盤上。

          將 token 返回給移動端,移動端將 token 存入在本地,往后移動端都通過 token 訪問服務(wù)端 API ,當(dāng)然除了 token 之外,還需要攜帶設(shè)備信息,因?yàn)?token 可能會被劫持。帶上設(shè)備信息之后,就算 token 被劫持也沒有關(guān)系,因?yàn)?strong>設(shè)備信息是唯一的。

          總結(jié):設(shè)備信息加token唯一確定用戶,完成登錄認(rèn)證


          2)二維碼掃碼登錄的原理

          1. 待掃描階段
          2. 待掃描階段也就是流程圖中 1~5 階段,即生成二維碼階段,這個階段跟移動端沒有關(guān)系,是 PC 端跟服務(wù)端的交互過程。
          3. 首先 PC 端攜帶設(shè)備信息向服務(wù)端發(fā)起生成二維碼請求,服務(wù)端會生成唯一的二維碼 ID,你可以理解為 UUID,并且將 二維碼 ID 跟 PC 設(shè)備信息關(guān)聯(lián)起來,這跟移動端登錄有點(diǎn)相似。
          4. PC 端接受到二維碼 ID 之后,將二維碼 ID 以二維碼的形式展示,等待移動端掃碼。此時在 PC 端會啟動一個定時器,輪詢查詢二維碼的狀態(tài)。如果移動端未掃描的話,那么一段時間后二維碼將會失效。

          總結(jié):PC端設(shè)備信息==>服務(wù)端生成二維碼==> PC端顯示==>定時器輪詢二維碼狀態(tài)

          1. 已掃描待確認(rèn)階段
          2. 流程圖中第 6 ~ 10 階段,我們在 PC 端登錄微信時,手機(jī)掃碼后,PC 端的二維碼會變成已掃碼,請在手機(jī)端確認(rèn)。這個階段是移動端跟服務(wù)端交互的過程。
          3. 首先移動端掃描二維碼,獲取二維碼 ID,然后將手機(jī)端登錄的信息憑證(token)和 二維碼 ID 作為參數(shù)發(fā)送給服務(wù)端,此時的手機(jī)一定是登錄的,不存在沒登錄的情況。
          4. 服務(wù)端接受請求后,會將 token 與二維碼 ID 關(guān)聯(lián),為什么需要關(guān)聯(lián)呢?你想想,我們使用微信時,移動端退出, PC 端是不是也需要退出,這個關(guān)聯(lián)就有點(diǎn)把子作用了。然后會生成一個一次性 token,這個 token 會返回給移動端,一次性 token 用作確認(rèn)時候的憑證。
          5. PC 端的定時器,會輪詢到二維碼的狀態(tài)已經(jīng)發(fā)生變化,會將 PC 端的二維碼更新為已掃描,請確認(rèn)。

          總結(jié):手機(jī)掃碼==>手機(jī)端token+二維碼ID發(fā)送到服務(wù)端==>服務(wù)器關(guān)聯(lián)token和二維碼ID ==> 生成token返回移動端 ==> PC端二維碼狀態(tài)更新

          1. 已確認(rèn)
          2. 流程圖中的 第 11 ~ 15 步驟,這是掃碼登錄的最后階段,移動端攜帶上一步驟中獲取的臨時 token ,確認(rèn)登錄,服務(wù)端校對完成后,會更新二維碼狀態(tài),并且給 PC 端生成一個正式的 token ,后續(xù) PC 端就是持有這個 token 訪問服務(wù)端。
          3. PC 端的定時器,輪詢到了二維碼狀態(tài)為登錄狀態(tài),并且會獲取到了生成的 token ,完成登錄,后續(xù)訪問都基于 token 完成。
          4. 在服務(wù)器端會跟手機(jī)端一樣,維護(hù)著 token 跟二維碼、PC 設(shè)備信息、賬號等信息。

          總結(jié):PC端獲取生成的token==> 完成登錄==>正常訪問(基于此token)

          八、前端文件下載

          1、實(shí)現(xiàn)方法

          1)form表單提交

          為一個下載按鈕添加click事件,點(diǎn)擊時動態(tài)生成一個表單,利用表單提交的功能來實(shí)現(xiàn)文件的下載

          /**
           * 下載文件
           * @param {String} path - 請求的地址
           * @param {String} fileName - 文件名
           */
          function downloadFile (downloadUrl, fileName) {
              // 創(chuàng)建表單
              const formObj = document.createElement('form');
              formObj.action = downloadUrl;
              formObj.method = 'get';
              formObj.style.display = 'none';
              // 創(chuàng)建input,主要是起傳參作用
              const formItem = document.createElement('input');
              formItem.value = fileName; // 傳參的值
              formItem.name = 'fileName'; // 傳參的字段名
              // 插入到網(wǎng)頁中
              formObj.appendChild(formItem);
              document.body.appendChild(formObj);
              formObj.submit(); // 發(fā)送請求
              document.body.removeChild(formObj); // 發(fā)送完清除掉
          }
          

          2)a標(biāo)簽的download

          <a href="example.jpg" download>點(diǎn)擊下載</a>
          
          <a href="example.jpg" download="test">點(diǎn)擊下載</a> // 指定文件名
          
          // 檢測瀏覽器是否支持download屬性
          const isSupport = 'download' in document.createElement('a');
          

          3)open或location.href

          本質(zhì)上和a標(biāo)簽訪問下載鏈接一樣

          window.open('downloadFile.zip');
          
          location.href = 'downloadFile.zip';
          

          4)Blob對象

          調(diào)用api,將文件流轉(zhuǎn)為Blob二進(jìn)制對象,

          注:IE10以下不支持。

          思路: 發(fā)請求獲取二進(jìn)制數(shù)據(jù),轉(zhuǎn)化為Blob對象,利用URL.createObjectUrl生成url地址,賦值在a標(biāo)簽的href屬性上,結(jié)合download進(jìn)行下載。

          /**
           * 下載文件
           * @param {String} path - 下載地址/下載請求地址。
           * @param {String} name - 下載文件的名字/重命名(考慮到兼容性問題,最好加上后綴名)
           */
          downloadFile (path, name) {
              const xhr = new XMLHttpRequest();
              xhr.open('get', path);
              xhr.responseType = 'blob';
              xhr.send();
              xhr.onload = function () {
                  if (this.status === 200 || this.status === 304) {
                      // 如果是IE10及以上,不支持download屬性,采用msSaveOrOpenBlob方法,但是IE10以下也不支持msSaveOrOpenBlob
                      if ('msSaveOrOpenBlob' in navigator) {
                          navigator.msSaveOrOpenBlob(this.response, name);
                          return;
                      }
                      /* 
                        如果發(fā)送請求時不設(shè)置xhr.responseType = 'blob',
                        默認(rèn)ajax請求會返回DOMString類型的數(shù)據(jù),即字符串。
                        此時需要使用兩處注釋的代碼,對返回的文本轉(zhuǎn)化為Blob對象,然后創(chuàng)建blob url,
                        此時需要注釋掉原本的const url = URL.createObjectURL(target.response)。
                      */
                      /* 
                      const blob = new Blob([this.response], { type: xhr.getResponseHeader('Content-Type') });
                      const url = URL.createObjectURL(blob);
                      */
                      const url = URL.createObjectURL(this.response); // 使用上面則注釋此行
                      const a = document.createElement('a');
                      a.style.display = 'none';
                      a.href = url;
                      a.download = name;
                      document.body.appendChild(a);
                      a.click();
                      document.body.removeChild(a);
                      URL.revokeObjectURL(url);
                  }
              };
          }
          
          // 上面方法本地測試有時會有跨域問題,下面使用axios重寫一下
          // 已經(jīng)配置好proxy
          downloadFile (path, name) {
              axios.get({
                url: path,
                method: 'get'
              }).then(res => {
                const blob = new Blob([res.data], { type: res.headers['content-type'] });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.style.display = 'none';
                a.href = url;
                a.download = name;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
              })
          }
          

          該方法不能缺少a標(biāo)簽的download屬性的設(shè)置。

          因?yàn)榘l(fā)請求時已設(shè)置返回數(shù)據(jù)類型為Blob類型(xhr.responseType = 'blob'),所以target.response就是一個Blob對象,打印出來會看到兩個屬性size和type。雖然type屬性已指定了文件的類型,但是為了穩(wěn)妥起見,還是在download屬性值里指定后綴名,如Firefox不指定下載下來的文件就會不識別類型。

          5)利用Base64

          用法跟上面用Blob大同小異,基本上思路一樣

          不同點(diǎn): 上面是利用Blob對象生成Blob URL, 這里則是生成Data URL,即base64編碼后的url形式。

          /**
           * 下載文件
           * @param {String} path - 下載地址/下載請求地址。
           * @param {String} name - 下載文件的名字(考慮到兼容性問題,最好加上后綴名)
           */
          downloadFile (path, name) {
              const xhr = new XMLHttpRequest();
              xhr.open('get', path);
              xhr.responseType = 'blob';
              xhr.send();
              xhr.onload = function () {
                  if (this.status === 200 || this.status === 304) {
                      const fileReader = new FileReader();
                      fileReader.readAsDataURL(this.response);
                      fileReader.onload = function () {
                          const a = document.createElement('a');
                          a.style.display = 'none';
                          a.href = this.result;
                          a.download = name;
                          document.body.appendChild(a);
                          a.click();
                          document.body.removeChild(a);
                      };
                  }
              };
          }
          

          2、如何獲取文件名

          返回文件流的時候,在瀏覽器上觀察接口返回的信息,會看到有這么一個header:Content-Disposition

          其中包含了文件名:filename=和filename*=可以截取這段字符串中的這兩個字段值了

          // xhr是XMLHttpRequest對象
          const content = xhr.getResponseHeader('content-disposition'); // 注意是全小寫,自定義的header也是全小寫
          if (content) {
              let name1 = content.match(/filename=(.*);/)[1]; // 獲取filename的值
              let name2 = content.match(/filename*=(.*)/)[1]; // 獲取filename*的值
              name1 = decodeURIComponent(name1);
              name2 = decodeURIComponent(name2.substring(6)); // 這個下標(biāo)6就是UTF-8''
          }
          

          九、滾動加載

          監(jiān)聽頁面滾動事件,分析clientHeightscrollTopscrollHeight三者的屬性關(guān)系。

          window.addEventListener('scroll', function() {
            const clientHeight = document.documentElement.clientHeight;
            const scrollTop = document.documentElement.scrollTop;
            const scrollHeight = document.documentElement.scrollHeight;
            if (clientHeight + scrollTop >= scrollHeight) {
              // 檢測到滾動至頁面底部,進(jìn)行后續(xù)操作
              // ...
            }
          }, false);
          

          十、渲染大數(shù)據(jù)

          渲染大數(shù)據(jù)時,合理使用createDocumentFragment和requestAnimationFrame,將操作切分為一小段一小段執(zhí)行。

          setTimeout(() => {
            // 插入十萬條數(shù)據(jù)
            const total = 100000;
            // 一次插入的數(shù)據(jù)
            const once = 20;
            // 插入數(shù)據(jù)需要的次數(shù)
            const loopCount = Math.ceil(total / once);
            let countOfRender = 0;
            const ul = document.querySelector('ul');
            // 添加數(shù)據(jù)的方法
            function add() {
              const fragment = document.createDocumentFragment();
              for(let i = 0; i < once; i++) {
                const li = document.createElement('li');
                li.innerText = Math.floor(Math.random() * total);
                fragment.appendChild(li);
              }
              ul.appendChild(fragment);
              countOfRender += 1;
              loop();
            }
            function loop() {
              if(countOfRender < loopCount) {
                window.requestAnimationFrame(add);
              }
            }
            loop();
          }, 0)
          

          十一、VDOM轉(zhuǎn)真實(shí)DOM基本原理


          主站蜘蛛池模板: 国产精品毛片a∨一区二区三区 | 亚洲AV无码一区二区乱孑伦AS| 中文字幕人妻AV一区二区| 国产亚洲一区区二区在线| 中文字幕亚洲一区| 亚洲日韩一区二区三区| 日韩精品久久一区二区三区| 人妻内射一区二区在线视频| 日本亚洲国产一区二区三区| 日本精品少妇一区二区三区| 日韩电影一区二区| 中文字幕一区二区三区永久| 国产一区二区成人| 精品国产精品久久一区免费式 | 国产在线aaa片一区二区99 | 无码视频免费一区二三区| 中文乱码字幕高清一区二区| 国产SUV精品一区二区88| 亚洲国产AV无码一区二区三区 | 国产精品无码一区二区三级| 国产一区二区女内射| 韩国福利一区二区三区高清视频| 丰满岳乱妇一区二区三区| 国产精品成人国产乱一区| 亚洲欧美日韩一区二区三区| 精品少妇一区二区三区视频| 国产无吗一区二区三区在线欢| 日韩AV无码久久一区二区| 日韩精品一区二区午夜成人版| 精品无码AV一区二区三区不卡| 国产日韩一区二区三区在线观看 | 精品一区二区三区在线播放| 国产精品一区二区久久沈樵| 韩国资源视频一区二区三区| 亚洲国产韩国一区二区| 国内精品视频一区二区三区| 黑巨人与欧美精品一区| 在线观看国产一区亚洲bd| 国产精品熟女视频一区二区| 久夜色精品国产一区二区三区| 国产成人一区二区三区精品久久|