中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站關(guān)鍵詞怎么添加seo文章范文

網(wǎng)站關(guān)鍵詞怎么添加,seo文章范文,wordpress圖床推薦,營業(yè)執(zhí)照怎么做增項 在網(wǎng)站上操作源碼閱讀:classnames 源碼閱讀:classnames簡介源碼解讀indexdedupebind類型聲明 學(xué)習(xí)與收獲 源碼閱讀:classnames 簡介 classnames 一個簡單的 JavaScript 實用程序,用于有條件地將類名連接在一起。 可以通過 npm 包管理器從 n…

源碼閱讀:classnames

  • 源碼閱讀:classnames
    • 簡介
    • 源碼解讀
      • index
      • dedupe
      • bind
      • 類型聲明
    • 學(xué)習(xí)與收獲

源碼閱讀:classnames

簡介

classnames 一個簡單的 JavaScript 實用程序,用于有條件地將類名連接在一起。

可以通過 npm 包管理器從 npm 注冊表上下載:

npm install classnames

classNames 函數(shù)接受任意數(shù)量的參數(shù),可以是字符串或?qū)ο蟆?shù) 'foo' 是 { foo: true } 的縮寫。如果與給定鍵關(guān)聯(lián)的值是假的,則該鍵將不會包含在輸出中。

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'// 支持不同類型的參數(shù)同時傳入
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'// 數(shù)組將按照上述規(guī)則遞歸展平
const arr = ['b', { c: true, d: false }];
classNames('a', arr); // => 'a b c'
// 相當(dāng)于
classNames('a', 'b', { c: true, d: false }); // => 'a b c'let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true });

在 React 中使用:
下面這段代碼實現(xiàn)了一個具有交互功能的按鈕組件。按鈕的樣式類名將根據(jù)按鈕的狀態(tài)動態(tài)改變,從而實現(xiàn)按鈕按下和鼠標(biāo)懸停的反饋效果。

import React, { useState } from 'react';export default function Button (props) {const [isPressed, setIsPressed] = useState(false);const [isHovered, setIsHovered] = useState(false);let btnClass = 'btn';if (isPressed) btnClass += ' btn-pressed';else if (isHovered) btnClass += ' btn-over';return (<buttonclassName={btnClass}onMouseDown={() => setIsPressed(true)}onMouseUp={() => setIsPressed(false)}onMouseEnter={() => setIsHovered(true)}onMouseLeave={() => setIsHovered(false)}>{props.label}</button>);
}

而使用classnames庫來動態(tài)生成按鈕的類名:

import React, { useState } from 'react';
import classNames from 'classnames';export default function Button (props) {const [isPressed, setIsPressed] = useState(false);const [isHovered, setIsHovered] = useState(false);const btnClass = classNames({btn: true,'btn-pressed': isPressed,'btn-over': !isPressed && isHovered,});return (<buttonclassName={btnClass}onMouseDown={() => setIsPressed(true)}onMouseUp={() => setIsPressed(false)}onMouseEnter={() => setIsHovered(true)}onMouseLeave={() => setIsHovered(false)}>{props.label}</button>);
}
  • 'btn: true':鍵為btn,表示按鈕應(yīng)該包含類名 btn
  • 'btn-pressed': isPressed:鍵為btn-pressed,表示當(dāng)isPressedtrue時,按鈕應(yīng)該包含類名btn-pressed。
  • 'btn-over': !isPressed && isHovered:鍵為btn-over,表示當(dāng)isPressedfalseisHoveredtrue時,按鈕應(yīng)該包含類名btn-over。

因為可以將對象、數(shù)組和字符串參數(shù)混合在一起,所以支持可選的 className prop屬性也更簡單,因為結(jié)果中只包含真實參數(shù):

const btnClass = classNames('btn', this.props.className, {'btn-pressed': isPressed,'btn-over': !isPressed && isHovered,
});

此外,作者還提供了另外兩個版本:dedupe 版本和 bind 版本。

其中dedupe 版本可以正確地刪除類的重復(fù)數(shù)據(jù),并確保從結(jié)果集中排除后面參數(shù)中指定的虛假類。但是此版本速度較慢(大約 5 倍),因此它作為一個可選的版本。

const classNames = require('classnames/dedupe');classNames('foo', 'foo', 'bar'); // => 'foo bar'
classNames('foo', { foo: false, bar: true }); // => 'bar'

而另一個bind 版本可以讓你結(jié)合 css-modules,以便在組件中動態(tài)地添加或刪除 CSS 類名,同時保證 css-modules 的作用域。

css-modules 是一種在項目中使用局部作用域的 CSS 的方法。它通過給每個類名添加一個唯一的哈希值,確保類名在整個應(yīng)用程序中是唯一的,避免了全局作用域的類名沖突。

const classNames = require('classnames/bind');const styles = {foo: 'abc',bar: 'def',baz: 'xyz',
};const cx = classNames.bind(styles);const className = cx('foo', ['bar'], { baz: true }); // => 'abc def xyz'

下面是一個使用classnamesbind版本結(jié)合css-modules的示例:

import { useState } from 'react';
import classNames from 'classnames/bind';
import styles from './submit-button.css';const cx = classNames.bind(styles);export default function SubmitButton ({ store, form }) {const [submissionInProgress, setSubmissionInProgress] = useState(store.submissionInProgress);const [errorOccurred, setErrorOccurred] = useState(store.errorOccurred);const [valid, setValid] = useState(form.valid);const text = submissionInProgress ? 'Processing...' : 'Submit';const className = cx({base: true,inProgress: submissionInProgress,error: errorOccurred,disabled: valid,});return <button className={className}>{text}</button>;
}

源碼解讀

由于代碼比較短,這里便直接放源碼,并在其中加上了注釋,讀者可自行閱讀:

index

/*!Copyright (c) 2018 Jed Watson.Licensed under the MIT License (MIT), seehttp://jedwatson.github.io/classnames
*/
/* global define */(function () {'use strict';var hasOwn = {}.hasOwnProperty;function classNames() {// 用于存儲生成的類名數(shù)組var classes = [];for (var i = 0; i < arguments.length; i++) {// 獲取當(dāng)前參數(shù)var arg = arguments[i];// 如果參數(shù)為空或為false,則跳過if (!arg) continue;// 獲取參數(shù)的類型var argType = typeof arg;// 如果參數(shù)是字符串或數(shù)字,則直接添加到類名數(shù)組中if (argType === 'string' || argType === 'number') {classes.push(arg);} else if (Array.isArray(arg)) {if (arg.length) {// 如果參數(shù)是數(shù)組,則遞歸調(diào)用classnames函數(shù),并將數(shù)組作為參數(shù)傳入var inner = classNames.apply(null, arg);if (inner) {// 如果遞歸調(diào)用的結(jié)果不為空,則將結(jié)果添加到類名數(shù)組中classes.push(inner);}}} else if (argType === 'object') {// 判斷 object 是否是一個自定義對象// 因為原生的 JavaScript 對象(例如 Array、Object 等)的 toString 方法包含 [native code]if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')) {classes.push(arg.toString());continue;}for (var key in arg) {if (hasOwn.call(arg, key) && arg[key]) {// 如果參數(shù)是對象,并且對象的屬性值為真,則將屬性名添加到類名數(shù)組中classes.push(key);}}}}// 將類名數(shù)組通過空格連接成字符串,并返回return classes.join(' ');}// 判斷是否在CommonJS環(huán)境下,如果是,則將classNames賦值給module.exportsif (typeof module !== 'undefined' && module.exports) {classNames.default = classNames;module.exports = classNames;} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {// 如果在AMD環(huán)境下,則將classnames函數(shù)注冊為模塊,并將其命名為'classnames'define('classnames', [], function () {return classNames;});} else {// 在瀏覽器環(huán)境下,將classnames函數(shù)掛載到全局的window對象上window.classNames = classNames;}
}());

dedupe

/*!Copyright (c) 2018 Jed Watson.Licensed under the MIT License (MIT), seehttp://jedwatson.github.io/classnames
*/
/* global define */(function () {'use strict';var classNames = (function () {// 創(chuàng)建一個不繼承自O(shè)bject的空對象,以便后面可以跳過hasOwnProperty的檢查function StorageObject() {}StorageObject.prototype = Object.create(null);// 解析數(shù)組,將數(shù)組中的每個元素解析為classNamesfunction _parseArray (resultSet, array) {var length = array.length;for (var i = 0; i < length; ++i) {_parse(resultSet, array[i]);}}var hasOwn = {}.hasOwnProperty;// 解析數(shù)字,將數(shù)字作為classNames的屬性function _parseNumber (resultSet, num) {resultSet[num] = true;}// 解析對象,將對象的屬性作為classNames的屬性function _parseObject (resultSet, object) {// 判斷 object 是否是一個自定義對象// 因為原生的 JavaScript 對象(例如 Array、Object 等)的 toString 方法包含 [native code]if (object.toString !== Object.prototype.toString && !object.toString.toString().includes('[native code]')) {resultSet[object.toString()] = true;return;}for (var k in object) {if (hasOwn.call(object, k)) {// set value to false instead of deleting it to avoid changing object structure// https://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript/#de-referencing-misconceptionsresultSet[k] = !!object[k];}}}var SPACE = /\s+/;// 解析字符串,將字符串按照空格分割為數(shù)組,并將數(shù)組中的每個元素作為classNames的屬性function _parseString (resultSet, str) {var array = str.split(SPACE);var length = array.length;for (var i = 0; i < length; ++i) {resultSet[array[i]] = true;}}// 解析參數(shù),根據(jù)參數(shù)的類型調(diào)用相應(yīng)的解析函數(shù)function _parse (resultSet, arg) {if (!arg) return;var argType = typeof arg;// 處理字符串類型的參數(shù)// 'foo bar'if (argType === 'string') {_parseString(resultSet, arg);// 處理數(shù)組類型的參數(shù)// ['foo', 'bar', ...]} else if (Array.isArray(arg)) {_parseArray(resultSet, arg);// 處理對象類型的參數(shù)// { 'foo': true, ... }} else if (argType === 'object') {_parseObject(resultSet, arg);// 處理數(shù)字類型的參數(shù)// '130'} else if (argType === 'number') {_parseNumber(resultSet, arg);}}// 主函數(shù)function _classNames () {// 避免arguments泄漏var len = arguments.length;var args = Array(len);for (var i = 0; i < len; i++) {args[i] = arguments[i];}// 創(chuàng)建一個存儲classNames的對象var classSet = new StorageObject();// 解析參數(shù)并將結(jié)果存儲在classSet對象中_parseArray(classSet, args);var list = [];// 將classSet中值為true的屬性加入到list數(shù)組中for (var k in classSet) {if (classSet[k]) {list.push(k)}}return list.join(' ');}return _classNames;})();// 判斷是否在CommonJS環(huán)境下,如果是,則將classNames賦值給module.exportsif (typeof module !== 'undefined' && module.exports) {classNames.default = classNames;module.exports = classNames;} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {// 如果在AMD環(huán)境下,則將classnames函數(shù)注冊為模塊,并將其命名為'classnames'define('classnames', [], function () {return classNames;});} else {// 在瀏覽器環(huán)境下,將classnames函數(shù)掛載到全局的window對象上window.classNames = classNames;}
}());

bind

/*!Copyright (c) 2018 Jed Watson.Licensed under the MIT License (MIT), seehttp://jedwatson.github.io/classnames
*/
/* global define */(function () {'use strict';var hasOwn = {}.hasOwnProperty;function classNames () {// 用于存儲生成的類名數(shù)組var classes = [];for (var i = 0; i < arguments.length; i++) {// 獲取當(dāng)前參數(shù)var arg = arguments[i];// 如果參數(shù)為空或為false,則跳過if (!arg) continue;var argType = typeof arg;// 如果參數(shù)是字符串或數(shù)字,則直接添加到類名數(shù)組中if (argType === 'string' || argType === 'number') {classes.push(this && this[arg] || arg);} else if (Array.isArray(arg)) {// 如果參數(shù)是數(shù)組,則遞歸調(diào)用classnames函數(shù),并將數(shù)組作為參數(shù)傳入classes.push(classNames.apply(this, arg));} else if (argType === 'object') {// 判斷 object 是否是一個自定義對象// 因為原生的 JavaScript 對象(例如 Array、Object 等)的 toString 方法包含 [native code]if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')) {classes.push(arg.toString());continue;}for (var key in arg) {if (hasOwn.call(arg, key) && arg[key]) {// 如果參數(shù)是對象,并且對象的屬性值為真,則將屬性名添加到類名數(shù)組中classes.push(this && this[key] || key);}}}}return classes.join(' ');}// 判斷是否在CommonJS環(huán)境下,如果是,則將classNames賦值給module.exportsif (typeof module !== 'undefined' && module.exports) {classNames.default = classNames;module.exports = classNames;} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {// 如果在AMD環(huán)境下,則將classnames函數(shù)注冊為模塊,并將其命名為'classnames'define('classnames', [], function () {return classNames;});} else {// 在瀏覽器環(huán)境下,將classnames函數(shù)掛載到全局的window對象上window.classNames = classNames;}
}());

index.js 相比,這個版本增加了對this上下文的處理。

類型聲明

// 以下類型聲明主要用于定義一個名為 "classNames" 的命名空間和相關(guān)的類型。
// 在這個聲明中,"classNames" 命名空間中定義了一些類型和接口
declare namespace classNames {// "Value" 是一個聯(lián)合類型,表示可以接受的值的類型,包括字符串、數(shù)字、布爾值、未定義和空值type Value = string | number | boolean | undefined | null;// "Mapping" 是一個類型別名,表示一個鍵值對的集合,其中鍵是字符串,值可以是任何類型type Mapping = Record<string, unknown>;// "ArgumentArray" 是一個接口,繼承自數(shù)組類型 "Array<Argument>",表示一個參數(shù)數(shù)組,其中每個元素都是 "Argument" 類型interface ArgumentArray extends Array<Argument> {}// "ReadonlyArgumentArray" 是一個接口,繼承自只讀數(shù)組類型 "ReadonlyArray<Argument>",表示一個只讀的參數(shù)數(shù)組interface ReadonlyArgumentArray extends ReadonlyArray<Argument> {}// "Argument" 是一個聯(lián)合類型,表示可以作為參數(shù)的類型,可以是 "Value"、"Mapping"、"ArgumentArray" 或 "ReadonlyArgumentArray"type Argument = Value | Mapping | ArgumentArray | ReadonlyArgumentArray;
}// 定義了一個名為 "ClassNames" 的接口,它是一個函數(shù)類型,可以接受 "classNames.ArgumentArray" 類型的參數(shù),并返回一個字符串
interface ClassNames {(...args: classNames.ArgumentArray): string;default: ClassNames;
}declare const classNames: ClassNames;// 通過 "export as namespace" 來將 "classNames" 聲明為全局命名空間
export as namespace classNames;
// 使用 "export =" 來導(dǎo)出 "classNames",使其可以在其他模塊中使用
export = classNames;

學(xué)習(xí)與收獲

  1. 使用嚴(yán)格模式

在源碼開頭使用嚴(yán)格模式的主要原因是為了確保代碼的質(zhì)量和可靠性。嚴(yán)格模式可以幫助開發(fā)者避免一些常見的錯誤和不規(guī)范的語法,同時也提供了更嚴(yán)格的錯誤檢查和更清晰的錯誤提示。使用嚴(yán)格模式可以減少一些隱患,提高代碼的可維護(hù)性和可讀性。

此外,嚴(yán)格模式還可以禁止一些潛在的危險行為,例如禁止使用未聲明的變量、禁止對只讀屬性賦值、禁止刪除變量等。這可以提高代碼的安全性,減少一些潛在的漏洞和安全風(fēng)險。

因此,為了確保代碼的質(zhì)量、可靠性和安全性,許多開發(fā)者選擇在源碼開頭使用嚴(yán)格模式。這樣可以強(qiáng)制要求代碼符合更嚴(yán)格的規(guī)范,減少錯誤和潛在的問題,并提高代碼的可維護(hù)性和可讀性。

  1. 創(chuàng)建一個不繼承自 Object 的空對象

Object.create(null) 是一個創(chuàng)建一個新對象的方法,該對象沒有原型鏈,也就是沒有繼承任何屬性和方法。這意味著該對象沒有內(nèi)置的屬性和方法,只能通過直接賦值來添加屬性和方法。使用 Object.create(null) 創(chuàng)建的對象被稱為“純凈對象”或“字典對象”,它適用于需要一個純粹的鍵值對集合而不需要繼承的場景。在這種對象中,鍵和值可以是任何類型的數(shù)據(jù),而不僅限于字符串。

在代碼中使用了 StorageObject.prototype = Object.create(null); 創(chuàng)建了一個不繼承自 Object 的空對象 StorageObject。這樣可以跳過 hasOwnProperty 的檢查,提高代碼的性能。

  1. 解析不同類型的參數(shù),包括字符串、數(shù)組、對象和數(shù)字

  2. 設(shè)計模式

單例模式是一種創(chuàng)建型設(shè)計模式,用于確保某個類只有一個實例,并提供一個全局訪問點(diǎn)來訪問該實例。

  • 單例模式:通過立即執(zhí)行函數(shù)包裹代碼,在執(zhí)行函數(shù)內(nèi)部創(chuàng)建了一個classNames對象,并將其賦值給全局變量window.classNames。這樣就保證了只有一個classNames對象存在,其他地方無法再創(chuàng)建新的classNames對象。

工廠模式是一種創(chuàng)建型設(shè)計模式,它提供了一種創(chuàng)建對象的接口,但具體創(chuàng)建的對象類型可以在運(yùn)行時確定。工廠模式可以分為簡單工廠模式、工廠方法模式和抽象工廠模式。

  1. 簡單工廠模式:也稱為靜態(tài)工廠模式,它直接使用一個靜態(tài)方法來創(chuàng)建對象。
  2. 工廠方法模式:也稱為虛擬工廠模式,它定義了一個工廠接口,并由不同的具體工廠實現(xiàn)來創(chuàng)建不同的對象。
  • 工廠模式:通過工廠函數(shù)_classNames()創(chuàng)建classNames對象,該對象可以根據(jù)不同的參數(shù)類型調(diào)用不同的解析函數(shù)來解析參數(shù),并將結(jié)果存儲在classSet對象中。
  1. 判斷運(yùn)行環(huán)境并導(dǎo)出 classNames

根據(jù)不同的運(yùn)行環(huán)境,判斷是否在 CommonJS 環(huán)境下、AMD 環(huán)境下或瀏覽器環(huán)境下。如果在 CommonJS 環(huán)境下,將 classNames 賦值給 module.exports;如果在 AMD 環(huán)境下,將 classNames 注冊為模塊,并命名為 'classnames';如果在瀏覽器環(huán)境下,將 classNames 掛載到全局的 window 對象上。

  1. TypeScript 類型聲明
  • 命名空間聲明:使用declare namespace可以定義一個命名空間,將相關(guān)的類型和接口組織在一起,防止命名沖突并提供模塊化的結(jié)構(gòu)。
  • 類型別名和聯(lián)合類型:使用 type 關(guān)鍵字可以定義類型別名,方便重復(fù)使用復(fù)雜的類型。聯(lián)合類型可以用于表示一個值可以是多個不同類型之一。
  • 接口和繼承:使用 interface 關(guān)鍵字可以定義接口,表示一種對象的結(jié)構(gòu)。接口可以繼承自其他接口,通過繼承可以復(fù)用已有的接口定義。
  • 函數(shù)類型:可以使用接口來定義函數(shù)類型,指定函數(shù)的參數(shù)類型和返回值類型。
  • 類型導(dǎo)出和模塊導(dǎo)入:使用 export 關(guān)鍵字可以將類型或值導(dǎo)出,使其可以在其他模塊中使用。使用 import 關(guān)鍵字可以在其他模塊中導(dǎo)入已導(dǎo)出的類型或值。
http://www.risenshineclean.com/news/31717.html

相關(guān)文章:

  • 學(xué)做粵菜的網(wǎng)站輔導(dǎo)班培訓(xùn)機(jī)構(gòu)
  • 開發(fā)中英文切換網(wǎng)站如何做網(wǎng)絡(luò)營銷大賽策劃書
  • 做網(wǎng)站需要什么條件廣告推廣媒體
  • 如何做盆栽蔬菜網(wǎng)站推廣普通話的意義30字
  • 大型網(wǎng)站技術(shù)架構(gòu):核心原理與案例分析16888精品貨源入口
  • 教我做網(wǎng)站立即優(yōu)化在哪里
  • 電影網(wǎng)站vps服務(wù)器廣告加盟
  • 互助盤網(wǎng)站開發(fā)萬網(wǎng)域名查詢接口
  • wordpress更新文章長沙官網(wǎng)seo服務(wù)
  • 中國六冶的網(wǎng)站誰做的今日的頭條新聞
  • 多語言網(wǎng)站建設(shè)推廣青島網(wǎng)站建設(shè)運(yùn)營推廣
  • 外貿(mào)推廣網(wǎng)站公司網(wǎng)站seo綜合查詢
  • 做競價要會做網(wǎng)站嗎優(yōu)化排名推廣技術(shù)網(wǎng)站
  • 做自媒體小視屏哪個網(wǎng)站好企業(yè)推廣文案
  • 哪些網(wǎng)站上可以做租車平臺推廣費(fèi)用一般是多少
  • 分銷微信小程序開發(fā)免費(fèi)seo工具
  • 網(wǎng)絡(luò)營銷模式課seo網(wǎng)站推廣可以自己搞嗎
  • 做亞馬遜網(wǎng)站一般發(fā)什么快遞海外推廣解決方案
  • 深圳微商城網(wǎng)站設(shè)計價格西安seo
  • 企業(yè)網(wǎng)站導(dǎo)航優(yōu)化成都做整站優(yōu)化
  • 高新區(qū)做網(wǎng)站讓顧客進(jìn)店的100條方法
  • 園洲做網(wǎng)站公司怎么做網(wǎng)站平臺
  • 邯鄲做網(wǎng)站的地方網(wǎng)絡(luò)設(shè)計
  • 可以做設(shè)計兼職的網(wǎng)站有哪些工作室搜外seo
  • 百姓網(wǎng)租房seo的定義是什么
  • 東勝網(wǎng)站建設(shè)網(wǎng)絡(luò)營銷策劃書的結(jié)構(gòu)
  • 用php寫的網(wǎng)站有哪些友情鏈接是免費(fèi)的嗎
  • 企業(yè)網(wǎng)站建設(shè)的困難和問題長春seo技術(shù)
  • 網(wǎng)站關(guān)鍵詞選擇軟文推廣文案
  • 哪個旅游網(wǎng)站做的比較好免費(fèi)平臺推廣