欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript手寫一個(gè)前端存儲(chǔ)工具庫(kù)

 更新時(shí)間:2023年02月14日 09:07:46   作者:jump__jump  
在項(xiàng)目開發(fā)的過(guò)程中,為了減少提高性能,減少請(qǐng)求,開發(fā)者往往需要將一些不易改變的數(shù)據(jù)放入本地緩存中。本文就來(lái)用JavaScript手寫一個(gè)前端存儲(chǔ)工具庫(kù),希望對(duì)大家有所幫助

在項(xiàng)目開發(fā)的過(guò)程中,為了減少提高性能,減少請(qǐng)求,開發(fā)者往往需要將一些不易改變的數(shù)據(jù)放入本地緩存中。如把用戶使用的模板數(shù)據(jù)放入 localStorage 或者 IndexedDB。代碼往往如下書寫。

// 這里將數(shù)據(jù)放入內(nèi)存中
let templatesCache = null;

// 用戶id,用于多賬號(hào)系統(tǒng)
const userId: string = '1';

const getTemplates = ({
  refresh = false
} = {
  refresh: false
}) => {
  // 不需要立即刷新,走存儲(chǔ)
  if (!refresh) {
    // 內(nèi)存中有數(shù)據(jù),直接使用內(nèi)存中數(shù)據(jù)
    if (templatesCache) {
      return Promise.resolve(templatesCache)
    }

    const key = `templates.${userId}`
    // 從 localStorage 中獲取數(shù)據(jù)
    const templateJSONStr = localStroage.getItem(key)
    
    if (templateJSONStr) {
      try {
        templatesCache = JSON.parse(templateJSONStr);
        return Promise.resolve(templatesCache)
      } catch () {
        // 解析失敗,清除 storage 中數(shù)據(jù)
        localStroage.removeItem(key)
      }
    }
  }

  // 進(jìn)行服務(wù)端掉用獲取數(shù)據(jù)
  return api.get('xxx').then(res => {
    templatesCache = cloneDeep(res)
    // 存入 本地緩存
    localStroage.setItem(key, JSON.stringify(templatesCache))
    return res
  })
};

可以看到,代碼非常冗余,同時(shí)這里的代碼還沒有處理數(shù)據(jù)版本、過(guò)期時(shí)間以及數(shù)據(jù)寫入等功能。如果再把這些功能點(diǎn)加入,代碼將會(huì)更加復(fù)雜,不易維護(hù)。

于是個(gè)人寫了一個(gè)小工具 storage-tools 來(lái)處理這個(gè)問題。

使用 storage-tools 緩存數(shù)據(jù)

該庫(kù)默認(rèn)使用 localStorage 作為數(shù)據(jù)源,開發(fā)者從庫(kù)中獲取 StorageHelper 工具類。

import { StorageHelper } from "storage-tools";

// 當(dāng)前用戶 id
const userId = "1";

// 構(gòu)建模版 store
// 構(gòu)建時(shí)候就會(huì)獲取 localStorage 中的數(shù)據(jù)放入內(nèi)存
const templatesStore = new StorageHelper({
  // 多賬號(hào)用戶使用 key
  storageKey: `templates.${userId}`,
  // 當(dāng)前數(shù)據(jù)版本號(hào),可以從后端獲取并傳入
  version: 1,
  // 超時(shí)時(shí)間,單位為 秒
  timeout: 60 * 60 * 24,
});

// 從內(nèi)存中獲取數(shù)據(jù)
const templates = templatesStore.getData();

// 沒有數(shù)據(jù),表明數(shù)據(jù)過(guò)期或者沒有存儲(chǔ)過(guò)
if (templates === null) {
  api.get("xxx").then((val) => {
    // 存儲(chǔ)數(shù)據(jù)到內(nèi)存中去,之后的 getData 都可以獲取到數(shù)據(jù)
    store.setData(val);

    // 閑暇時(shí)間將當(dāng)前內(nèi)存數(shù)據(jù)存儲(chǔ)到 localStorage 中
    requestIdleCallback(() => {
      // 期間內(nèi)可以多次掉用 setData
      store.commit();
    });
  });
}

StorageHelper 工具類支持了其他緩存源,代碼如下:

import { IndexedDBAdaptor, StorageAdaptor, StorageHelper } from "storage-tools";

// 當(dāng)前用戶 id
const userId = "1";

const sessionStorageStore = new StorageHelper({
  // 配置同上
  storageKey: `templates.${userId}`,
  version: 1,
  timeout: 60 * 60 * 24,
  // 適配器,傳入 sessionStorage
  adapter: sessionStorage,
});

const indexedDBStore = new StorageHelper({
  storageKey: `templates.${userId}`,
  version: 1,
  timeout: 60 * 60 * 24,
  // 適配器,傳入 IndexedDBAdaptor
  adapter: new IndexedDBAdaptor({
    dbName: "userInfo",
    storeName: "templates",
  }),
});

// IndexedDB 只能異步構(gòu)建,所以現(xiàn)在只能等待獲取構(gòu)建獲取完成
indexedDBStore.whenReady().then(() => {
  // 準(zhǔn)備完成后,我們就可以 getData 和 setData 了
  const data = indexedDBStore.getData();

  // 其余代碼
});

// 只需要有 setItem 和 getItem 就可以構(gòu)建 adaptor
class MemoryAdaptor implements StorageAdaptor {
  readonly cache = new Map();

  // 獲取 map 中數(shù)據(jù)
  getItem(key: string) {
    return this.cache.get(key);
  }

  setItem(key: string, value: string) {
    this.cache.set(key, value);
  }
}

const memoryStore = new StorageHelper({
  // 配置同上
  storageKey: `templates.${userId}`,
  version: 1,
  timeout: 60 * 60 * 24,
  // 適配器,傳入攜帶 getItem 和 setItem 對(duì)象
  adapter: new MemoryAdaptor(),
});

當(dāng)然了,我們還可以繼承 StorageHelper 構(gòu)建業(yè)務(wù)類。

// 也可以基于 StorageHelper 構(gòu)建業(yè)務(wù)類
class TemplatesStorage extends StorageHelper {
  // 傳入 userId 以及 版本
  constructor(userId: number, version: number) {
    super({
      storageKey: `templates.${userId}`,
      // 如果需要運(yùn)行時(shí)候更新,則可以動(dòng)態(tài)傳遞
      version,
      timeout: 60 * 60 * 24,
    });
  }

  // TemplatesStorage 實(shí)例
  static instance: TemplatesStorage;

  // 如果需要版本信息的話,
  static version: number = 0;

  static getStoreInstance() {
    // 獲取版本信息
    return getTemplatesVersion().then((newVersion) => {
      // 沒有構(gòu)建實(shí)例或者版本信息不相等,直接重新構(gòu)建
      if (
        newVersion !== TemplatesStorage.version || !TemplatesStorage.instance
      ) {
        TemplatesStorage.instance = new TemplatesStorage("1", newVersion);
        TemplatesStorage.version = newVersion;
      }

      return TemplatesStorage.instance;
    });
  }

  /**
   * 獲取模板緩存和 api 請(qǐng)求結(jié)合
   */
  getTemplates() {
    const data = super.getData();
    if (data) {
      return Promise.resolve(data);
    }
    return api.get("xxx").then((val) => {
      this.setTemplates(val);
      return super.getData();
    });
  }

  /**
   * 保存數(shù)據(jù)到內(nèi)存后提交到數(shù)據(jù)源
   */
  setTemplats(templates: any[]) {
    super.setData(templates);
    super.commit();
  }
}

/**
 * 獲取模版信息函數(shù)
 */
const getTemplates = () => {
  return TemplatesStorage.getStoreInstance().then((instance) => {
    return instance.getTemplates();
  });
};

針對(duì)于某些特定列表順序需求,我們還可以構(gòu)建 ListStorageHelper。

import { ListStorageHelper, MemoryAdaptor } from "../src";

// 當(dāng)前用戶 id
const userId = "1";

const store = new ListStorageHelper({
  storageKey: `templates.${userId}`,
  version: 1,
  // 設(shè)置唯一鍵 key,默認(rèn)為 'id'
  key: "searchVal",
  // 列表存儲(chǔ)最大數(shù)據(jù)量,默認(rèn)為 10
  maxCount: 100,
  // 修改數(shù)據(jù)后是否移動(dòng)到最前面,默認(rèn)為 true
  isMoveTopWhenModified: true,
  // 添加數(shù)據(jù)后是否是最前面, 默認(rèn)為 true
  isUnshiftWhenAdded: true,
});

store.setItem({ searchVal: "new game" });
store.getData();
// [{
//   searchVal: 'new game'
// }]

store.setItem({ searchVal: "new game2" });
store.getData();
// 會(huì)插入最前面
// [{
//   searchVal: 'new game2'
// }, {
//   searchVal: 'new game'
// }]

store.setItem({ searchVal: "new game" });
store.getData();
// 會(huì)更新到最前面
// [{
//   searchVal: 'new game'
// }, {
//   searchVal: 'new game2'
// }]

// 提交到 localStorage
store.commit();

storage-tools 項(xiàng)目演進(jìn)

任何項(xiàng)目都不是一觸而就的,下面是關(guān)于 storage-tools 庫(kù)的編寫思路。希望能對(duì)大家有一些幫助。

StorageHelper 支持 localStorage 存儲(chǔ)

項(xiàng)目的第一步就是支持本地儲(chǔ)存 localStorage 的存取。

// 獲取從 1970 年 1 月 1 日 00:00:00 UTC 到用戶機(jī)器時(shí)間的秒數(shù)
// 后續(xù)有需求也會(huì)向外提供時(shí)間函數(shù)配置,可以結(jié)合 sync-time 庫(kù)一起使用
const getCurrentSecond = () => parseInt(`${new Date().getTime() / 1000}`);

// 獲取當(dāng)前空數(shù)據(jù)
const getEmptyDataStore = (version: number): DataStore<any> => {
  const currentSecond = getCurrentSecond();
  return {
    // 當(dāng)前數(shù)據(jù)的創(chuàng)建時(shí)間
    createdOn: currentSecond,
    // 當(dāng)前數(shù)據(jù)的修改時(shí)間
    modifiedOn: currentSecond,
    // 當(dāng)前數(shù)據(jù)的版本
    version,
    // 數(shù)據(jù),空數(shù)據(jù)為 null
    data: null,
  };
};

class StorageHelper<T> {
  // 存儲(chǔ)的 key
  private readonly storageKey: string;
  // 存儲(chǔ)的版本信息
  private readonly version: number;

  // 內(nèi)存中數(shù)據(jù),方便隨時(shí)讀寫
  store: DataStore<T> | null = null;

  constructor({ storageKey, version }) {
    this.storageKey = storageKey;
    this.version = version || 1;

    this.load();
  }

  load() {
    const result: string | null = localStorage.getItem(this.storageKey);

    // 初始化內(nèi)存信息數(shù)據(jù)
    this.initStore(result);
  }

  private initStore(storeStr: string | null) {
    // localStorage 沒有數(shù)據(jù),直接構(gòu)建 空數(shù)據(jù)放入 store
    if (!storeStr) {
      this.store = getEmptyDataStore(this.version);
      return;
    }

    let store: DataStore<T> | null = null;

    try {
      // 開始解析 json 字符串
      store = JSON.parse(storeStr);

      // 沒有數(shù)據(jù)或者 store 沒有 data 屬性直接構(gòu)建空數(shù)據(jù)
      if (!store || !("data" in store)) {
        store = getEmptyDataStore(this.version);
      } else if (store.version !== this.version) {
        // 版本不一致直接升級(jí)
        store = this.upgrade(store);
      }
    } catch (_e) {
      // 解析失敗了,構(gòu)建空的數(shù)據(jù)
      store = getEmptyDataStore(this.version);
    }

    this.store = store || getEmptyDataStore(this.version);
  }

  setData(data: T) {
    if (!this.store) {
      return;
    }
    this.store.data = data;
  }

  getData(): T | null {
    if (!this.store) {
      return null;
    }
    return this.store?.data;
  }

  commit() {
    // 獲取內(nèi)存中的 store
    const store = this.store || getEmptyDataStore(this.version);
    store.version = this.version;

    const now = getCurrentSecond();
    if (!store.createdOn) {
      store.createdOn = now;
    }
    store.modifiedOn = now;

    // 存儲(chǔ)數(shù)據(jù)到 localStorage
    localStorage.setItem(this.storageKey, JSON.stringify(store));
  }

  /**
   * 獲取內(nèi)存中 store 的信息
   * 如 modifiedOn createdOn version 等信息
   */
  get(key: DataStoreInfo) {
    return this.store?.[key];
  }

  upgrade(store: DataStore<T>): DataStore<T> {
    // 獲取當(dāng)前的秒數(shù)
    const now = getCurrentSecond();
    // 看起來(lái)很像 getEmptyDataStore 代碼,但實(shí)際上是不同的業(yè)務(wù)
    // 不應(yīng)該因?yàn)榇a相似而合并,不利于后期擴(kuò)展
    return {
      // 只獲取之前的創(chuàng)建時(shí)間,如果沒有使用當(dāng)前的時(shí)間
      createdOn: store?.createdOn || now,
      modifiedOn: now,
      version: this.version,
      data: null,
    };
  }
}

StorageHelper 添加超時(shí)機(jī)制

添加超時(shí)機(jī)制很簡(jiǎn)單,只需要在 getData 的時(shí)候檢查一下數(shù)據(jù)即可。

class StorageHelper<T> {
  // 其他代碼 ...

  // 超時(shí)時(shí)間,默認(rèn)為 -1,即不超時(shí)
  private readonly timeout: number = -1;

  constructor({ storageKey, version, timeout }: StorageHelperParams) {
    // 傳入的數(shù)據(jù)是數(shù)字類型,且大于 0,就設(shè)定超時(shí)時(shí)間
    if (typeof timeout === "number" && timeout > 0) {
      this.timeout = timeout;
    }
  }

  getData(): T | null {
    if (!this.store) {
      return null;
    }

    // 如果小于 0 就沒有超時(shí)時(shí)間,直接返回?cái)?shù)據(jù),事實(shí)上不可能小于0
    if (this.timeout < 0) {
      return this.store?.data;
    }

    // 修改時(shí)間加超時(shí)時(shí)間大于當(dāng)前時(shí)間,則表示沒有超時(shí)
    // 注意,每次 commit 都會(huì)更新 modifiedOn
    if (getCurrentSecond() < (this.store?.modifiedOn || 0) + this.timeout) {
      return this.store?.data;
    }

    // 版本信息在最開始時(shí)候處理過(guò)了,此處直接返回 null
    return null;
  }
}

StorageHelper 添加其他存儲(chǔ)適配

此時(shí)我們可以添加其他數(shù)據(jù)源適配,方便開發(fā)者自定義 storage。

/**
 * 適配器接口,存在 getItem 以及 setItem
 */
interface StorageAdaptor {
  getItem: (key: string) => string | Promise<string> | null;
  setItem: (key: string, value: string) => void;
}

class StorageHelper<T> {
  // 其他代碼 ...

  // 非瀏覽器環(huán)境不具備 localStorage,所以不在此處直接構(gòu)造
  readonly adapter: StorageAdaptor;

  constructor({ storageKey, version, adapter, timeout }: StorageHelperParams) {
    // 此處沒有傳遞 adapter 就會(huì)使用 localStorage
    // adapter 對(duì)象必須有 getItem 和 setItem
    // 此處沒有進(jìn)一步判斷 getItem 是否為函數(shù)以及 localStorage 是否存在
    // 沒有辦法限制住所有的異常
    this.adapter = adapter && "getItem" in adapter && "setItem" in adapter
      ? adapter
      : localStorage;

    this.load();
  }

  load() {
    // 此處改為 this.adapter
    const result: Promise<string> | string | null = this.adapter.getItem(
      this.storageKey,
    );
  }

  commit() {
    // 此處改為 this.adapter
    this.adapter.setItem(this.storageKey, JSON.stringify(store));
  }
}

StorageHelper 添加異步獲取

如有些數(shù)據(jù)源需要異步構(gòu)建并獲取數(shù)據(jù),例如 IndexedDB 。這里我們先建立一個(gè) IndexedDBAdaptor 類。

import { StorageAdaptor } from "../utils";

// 把 indexedDB 的回調(diào)改為 Promise
function promisifyRequest<T = undefined>(
  request: IDBRequest<T> | IDBTransaction,
): Promise<T> {
  return new Promise<T>((resolve, reject) => {
    // @ts-ignore
    request.oncomplete = request.onsuccess = () => resolve(request.result);
    // @ts-ignore
    request.onabort = request.onerror = () => reject(request.error);
  });
}

/**
 * 創(chuàng)建并返回 indexedDB 的句柄
 */
const createStore = (
  dbName: string,
  storeName: string,
  upgradeInfo: IndexedDBUpgradeInfo = {},
): UseStore => {
  const request = indexedDB.open(dbName);

  /**
   * 創(chuàng)建或者升級(jí)時(shí)候會(huì)調(diào)用 onupgradeneeded
   */
  request.onupgradeneeded = () => {
    const { result: store } = request;
    if (!store.objectStoreNames.contains(storeName)) {
      const { options = {}, indexList = [] } = upgradeInfo;
      // 基于 配置項(xiàng)生成 store
      const store = request.result.createObjectStore(storeName, { ...options });

      // 建立索引
      indexList.forEach((index) => {
        store.createIndex(index.name, index.keyPath, index.options);
      });
    }
  };

  const dbp = promisifyRequest(request);

  return (txMode, callback) =>
    dbp.then((db) =>
      callback(db.transaction(storeName, txMode).objectStore(storeName))
    );
};

export class IndexedDBAdaptor implements StorageAdaptor {
  private readonly store: UseStore;

  constructor({ dbName, storeName, upgradeInfo }: IndexedDBAdaptorParams) {
    this.store = createStore(dbName, storeName, upgradeInfo);
  }

  /**
   * 獲取數(shù)據(jù)
   */
  getItem(key: string): Promise<string> {
    return this.store("readonly", (store) => promisifyRequest(store.get(key)));
  }

  /**
   * 設(shè)置數(shù)據(jù)
   */
  setItem(key: string, value: string) {
    return this.store("readwrite", (store) => {
      store.put(value, key);
      return promisifyRequest(store.transaction);
    });
  }
}

對(duì) StorageHelper 類做如下改造

type CreateDeferredPromise = <TValue>() => CreateDeferredPromiseResult<TValue>;

// 劫持一個(gè) Promise 方便使用
export const createDeferredPromise: CreateDeferredPromise = <T>() => {
  let resolve!: (value: T | PromiseLike<T>) => void;
  let reject!: (reason?: any) => void;

  const promise = new Promise<T>((res, rej) => {
    resolve = res;
    reject = rej;
  });

  return {
    currentPromise: promise,
    resolve,
    reject,
  };
};

export class StorageHelper<T> {
  // 是否準(zhǔn)備好了
  ready: CreateDeferredPromiseResult<boolean> = createDeferredPromise<
    boolean
  >();

  constructor({ storageKey, version, adapter, timeout }: StorageHelperParams) {
    this.load();
  }

  load() {
    const result: Promise<string> | string | null = this.adapter.getItem(
      this.storageKey,
    );

    // 檢查一下當(dāng)前的結(jié)果是否是 Promise 對(duì)象
    if (isPromise(result)) {
      result
        .then((res) => {
          this.initStore(res);
          // 準(zhǔn)備好了
          this.ready.resolve(true);
        })
        .catch(() => {
          this.initStore(null);
          // 準(zhǔn)備好了
          this.ready.resolve(true);
        });
    } else {
      // 不是 Promise 直接構(gòu)建 store
      this.initStore(result);
      // 準(zhǔn)備好了
      this.ready.resolve(true);
    }
  }

  // 詢問是否做好準(zhǔn)備
  whenReady() {
    return this.ready.currentPromise;
  }
}

如此,我們就完成了 StorageHelper 全部代碼。

列表輔助類 ListStorageHelper

ListStorageHelper 基于 StorageHelper 構(gòu)建,方便特定業(yè)務(wù)使用。

// 數(shù)組最大數(shù)量
const STORE_MAX_COUNT: number = 10;

export class ListStorageHelper<T> extends StorageHelper<T[]> {
  // 主鍵,默認(rèn)為 id
  readonly key: string = "id";
  // 存儲(chǔ)最大數(shù)量,默認(rèn)為 10
  readonly maxCount: number = STORE_MAX_COUNT;

  // 是否添加在最前面
  readonly isUnshiftWhenAdded: boolean = true;
  // 修改后是否放入最前面
  readonly isMoveTopWhenModified: boolean = true;

  constructor({
    maxCount,
    key,
    isMoveTopWhenModified = true,
    isUnshiftWhenAdded = true,
    storageKey,
    version,
    adapter,
    timeout,
  }: ListStorageHelperParams) {
    super({ storageKey, version, adapter, timeout });
    this.key = key || "id";

    // 設(shè)置配置項(xiàng)
    if (typeof maxCount === "number" && maxCount > 0) {
      this.maxCount = maxCount;
    }

    if (typeof isMoveTopWhenModified === "boolean") {
      this.isMoveTopWhenModified = isMoveTopWhenModified;
    }

    if (typeof this.isUnshiftWhenAdded === "boolean") {
      this.isUnshiftWhenAdded = isUnshiftWhenAdded;
    }
  }

  load() {
    super.load();
    // 沒有數(shù)據(jù),設(shè)定為空數(shù)組方便統(tǒng)一
    if (!this.store!.data) {
      this.store!.data = [];
    }
  }

  getData = (): T[] => {
    const items = super.getData() || [];
    // 檢查數(shù)據(jù)長(zhǎng)度并移除超過(guò)的數(shù)據(jù)
    this.checkThenRemoveItem(items);
    return items;
  };

  setItem(item: T) {
    if (!this.store) {
      throw new Error("Please complete the loading load first");
    }

    const items = this.getData();

    // 利用 key 去查找存在數(shù)據(jù)索引
    const index = items.findIndex(
      (x: any) => x[this.key] === (item as any)[this.key],
    );

    // 當(dāng)前有數(shù)據(jù),是更新
    if (index > -1) {
      const current = { ...items[index], ...item };
      // 更新移動(dòng)數(shù)組數(shù)據(jù)
      if (this.isMoveTopWhenModified) {
        items.splice(index, 1);
        items.unshift(current);
      } else {
        items[index] = current;
      }
    } else {
      // 添加
      this.isUnshiftWhenAdded ? items.unshift(item) : items.push(item);
    }
    // 檢查并移除數(shù)據(jù)
    this.checkThenRemoveItem(items);
  }

  removeItem(key: string | number) {
    if (!this.store) {
      throw new Error("Please complete the loading load first");
    }
    const items = this.getData();
    const index = items.findIndex((x: any) => x[this.key] === key);
    // 移除數(shù)據(jù)
    if (index > -1) {
      items.splice(index, 1);
    }
  }

  setItems(items: T[]) {
    if (!this.store) {
      return;
    }
    this.checkThenRemoveItem(items);
    // 批量設(shè)置數(shù)據(jù)
    this.store.data = items || [];
  }

  /**
   * 多添加一個(gè)方法 getItems,等同于 getData 方法
   */
  getItems() {
    if (!this.store) {
      return null;
    }
    return this.getData();
  }

  checkThenRemoveItem = (items: T[]) => {
    if (items.length <= this.maxCount) {
      return;
    }
    items.splice(this.maxCount, items.length - this.maxCount);
  };
}

該類繼承了 StorageHelper,我們依舊可以直接調(diào)用 commit 提交數(shù)據(jù)。如此我們就不需要維護(hù)復(fù)雜的 storage 存取邏輯了。

代碼都在 storage-tools 中,歡迎各位提交 issue 以及 pr。

到此這篇關(guān)于JavaScript手寫一個(gè)前端存儲(chǔ)工具庫(kù)的文章就介紹到這了,更多相關(guān)JavaScript前端存儲(chǔ)工具庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • js實(shí)現(xiàn)簡(jiǎn)單圖片拖拽效果

    js實(shí)現(xiàn)簡(jiǎn)單圖片拖拽效果

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)簡(jiǎn)單圖片拖拽效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-02-02
  • JS匿名函數(shù)和匿名自執(zhí)行函數(shù)概念與用法分析

    JS匿名函數(shù)和匿名自執(zhí)行函數(shù)概念與用法分析

    這篇文章主要介紹了JS匿名函數(shù)和匿名自執(zhí)行函數(shù)概念與用法,結(jié)合實(shí)例形式分析了匿名函數(shù)和匿名自執(zhí)行函數(shù)的概念、功能、應(yīng)用場(chǎng)景及相關(guān)使用技巧,需要的朋友可以參考下
    2018-03-03
  • uniapp中renderjs使用與傳值問題

    uniapp中renderjs使用與傳值問題

    renderjs是一個(gè)運(yùn)行在視圖層的js,它只支持app-vue和h5,下面這篇文章主要給大家介紹了關(guān)于uniapp中renderjs使用與傳值問題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • 使用JavaScript實(shí)現(xiàn)文本收起展開(省略)功能

    使用JavaScript實(shí)現(xiàn)文本收起展開(省略)功能

    省略號(hào),作為一種常見的文本處理方式,在很多情況下都十分常見,特別是當(dāng)我們需要在省略號(hào)后面添加額外文字時(shí),本文為大家介紹了使用JavaScript實(shí)現(xiàn)文本收起展開功能的相關(guān)方法,希望對(duì)大家有所幫助
    2024-04-04
  • JavaScript的parseInt 取整使用

    JavaScript的parseInt 取整使用

    JavaScript 是弱類型語(yǔ)言, 為了保證數(shù)值的有效性, 在處理數(shù)值的時(shí)候, 我們可以對(duì)數(shù)值字符串進(jìn)行強(qiáng)行轉(zhuǎn)換. 如 parseInt 取整和 parseFloat 取浮點(diǎn)數(shù)
    2011-05-05
  • JS+JQuery實(shí)現(xiàn)無(wú)縫連接輪播圖

    JS+JQuery實(shí)現(xiàn)無(wú)縫連接輪播圖

    這篇文章主要介紹了JS+JQuery實(shí)現(xiàn)無(wú)縫連接輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • JS清空上傳控件input(type="file")的值的代碼

    JS清空上傳控件input(type="file")的值的代碼

    最近做的一個(gè)小功能,需要清空<input type="file">的值,但上傳控件<input type="file">的值不能通過(guò)JavaScript來(lái)修改。
    2008-11-11
  • 微信小程序嵌入騰訊視頻源過(guò)程詳解

    微信小程序嵌入騰訊視頻源過(guò)程詳解

    這篇文章主要介紹了微信小程序嵌入騰訊視頻源過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • webpack打包時(shí)如何修改文件名的實(shí)現(xiàn)示例

    webpack打包時(shí)如何修改文件名的實(shí)現(xiàn)示例

    本文主要介紹了webpack打包時(shí)如何修改文件名的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 如何用threejs實(shí)現(xiàn)實(shí)時(shí)多邊形折射

    如何用threejs實(shí)現(xiàn)實(shí)時(shí)多邊形折射

    這篇文章主要介紹了如何用threejs實(shí)現(xiàn)實(shí)時(shí)多邊形折射,對(duì)three.js庫(kù)感興趣的同學(xué),可以參考下
    2021-05-05

最新評(píng)論