【工作纪实】- 编程方法记录

77 阅读3分钟

JS 获取URL中的参数

使用URLSearchParams方法

此方法使用 URLSearchParams 类来解析 search 中的参数,然后使用 get 方法获取对应的参数

const urlParams = new URLSearchParams(window.location.search);
const showFrom = urlParams.get('show_from');
const time = urlParams.get('time');

console.log(' == show_from == ', showFrom);
console.log(' == time == ', time); // null

直接解析 window.location.search

const search = window.location.search;
if (search !== '') {
    const obj = search.split('?')[1].split('&')
    let obj1 = []

    obj.forEach(key => {
        const [key1, value] = key.split('=')
        obj1[key1] = value
    });

    console.error(' -- show_from -- ', obj1.show_from);
    console.error(' -- time -- ', obj1.time); // undefined
}

JS 中对象深拷贝的方式

JSON.parse(JSON.stringify(obj))

这种方式通过将对象转换为 JSON 字符串,然后再将 JSON 字符串转换回对象,实现深拷贝

function deepCopy(value) {
    if (typeof value !== object || value === null) return value
    return JSON.parse(JSON.stringify(value))
}

Object.assign()

这种方式通过将原对象的属性复制到一个新对象中,实现深拷贝 但是,如果原对象中有嵌套对象,不适用。需要递归调用,否则嵌套的对象会变成浅拷贝

function deepCopy(obj) {
    return Object.assign({}, obj)
}

const obj = { a: 1, b: { c: 2 } }
let newObj = deepCopy1(obj)
console.log(' == obj == ', obj); // { a: 1, b: { c: 2 } }
console.log(' == newObj == ', newObj); // { a: 1, b: { c: 2 } }

obj.a = 3
console.log(' == obj == ', obj); // { a: 3, b: { c: 2 } }
console.log(' == newObj == ', newObj); // { a: 1, b: { c: 2 } }

obj.b.c = 4
console.log(' == obj == ', obj); // { a: 3, b: { c: 4 } }
console.log(' == newObj == ', newObj); // { a: 1, b: { c: 4 } }

递归函数

通过递归函数来实现深拷贝,可以处理任意深度的嵌套对象

function deepCopy(value) {
    if (typeof value !== object || value === null) return value
    const result  = Array.isArray(value) ? [] : {}

    for (key in value) {
        result[key] = deepCopy(value[key])
    }
}

Lodash 的 cloneDeep()

Lodash 是一个流行的 JavaScript 库,它提供了一个名为 cloneDeep() 的函数,可以实现深拷贝

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

const _ = window._;
const obj = { a: 1, b: { c: 2 } }
const newObj = _.cloneDeep(obj)

定时更新日期

需求描述

若页面展示一个页面更新日期为:2024.09.05,为了避免在之后需要更新这个日期时进行项目的发版,或者项目中很多页面都展示了这个日期。弄一个定时更新日期的函数去更新这个页面的时间

实现思路

  1. 周三早上八点之后访问,则更新成当前的日期(也就是本周三日期)

  2. 其他时间访问,更新成周三的日期

    2.1. 比如周一、二访问,日期更新成上周周三的

    2.2. 周四、五访问,日期是本周周三的

  3. 一周更新一次时间(周三八点之后访问时更新)

编码实现

function updateDate() {
  const date = new Date(); // Thu Sep 05 2024 20:43:21 GMT+0800 (中国标准时间)
  const dayOfWeek  = date.getDay(); // 获取日期(是周几)
  const hour = date.getHours(); // 获取当前小时

  const isWednesday = dayOfWeek == 3 && hour >= 8; // 是否周三早上八点后访问
  const wednesdayDate = isWednesday ? date : getPreviousWednesday(date);

  const year = wednesdayDate.getFullYear();
  const month = String(wednesdayDate.getMonth() + 1).padStart(2, '0');
  const day = String(wednesdayDate.getDate()).padStart(2, '0');

  $('.update-date').text(year + '.' + month + '.' + day);
}

function getPreviousWednesday(date) {
  const wednesdayDate = new Date(date);
  /**
   * wedensday.getDate():获取当前日期 - 多少号。例如:27号
   * wedensday.getDay():获取当前日期 - 周几。例如 27号是周二 => 2
   */
  if (wednesdayDate.getDay() < 3) {
    wednesdayDate.setDate(wednesdayDate.getDate() - (wednesdayDate.getDay() + 4));
  } else {
    wednesdayDate.setDate(wednesdayDate.getDate() - (wednesdayDate.getDay() - 3));
  }
  return wednesdayDate;
}

new Date().setDate()的作用

new Date().setDate() 的作用是,设置对应日期的日期 比如如果要获取本月(写这篇文章时是24年9月)27号的日期是什么

const date = new Date();
date.setDate(27); // 1727441498872
return date; // Fri Sep 27 2024 20:51:38 GMT+0800 (中国标准时间)

localStorage设置过期时间

需求描述

localStorage 是浏览器的一种持久化存储机制。其存储的数据除非手动删除,或者浏览器的存储空间被清除,否则永远会存在。其本身不支持设置过期时间,那么如何通过编码为其设置一个过期时间,让数据到期后自动删除呢?

实现思路

  1. 在设置数据存储时,存储一个对象,对象属性设置一个过期时间

  2. 在获取数据时,先将当前时间与缓存数据的过期时间进行对比

    2.1 如果当前时间大于过期时间,说明数据已过期,则删除

    2.2 如果当前时间小于过期时间,说明在有效期内,则直接返回

编码实现

// 存储值的方法
const setLocalStorageWithExpires = (key, value, expiresTime) => {
    const expireDate = new Date().getTime() + expiresTime * 1000;
    localStorage.setItem(key, JSON.stringify({ value, expireDate }));
};

// 获取值的方法
const getLocalStorageWithExpires = (key) => {
    const storedValue = localStorage.getItem(key);
    if (!storedValue) {
        return null;
    }
    const { value, expireDate } = JSON.parse(storedValue);

    // 判断是否过期了 
    if (new Date().getTime() > expireDate) {
        // 过期,则移除
        localStorage.removeItem(key);
        return null;
    }
    return value;
};

// 调用
setLocalStorageWithExpire('myKey', 'myValue', 3600); // 1小时

const value = getLocalStorageWithExpire('myKey');
if (value) {
    console.log(value);
} else {
    console.log('值已过期');
}

注意

这种方法虽然可以实现过期时间的功能,但是需要注意的是,localStorage 的存储空间是有限的,所以不建议存储大量数据。 另外,可以使用 sessionStorage,它本身支持会话级别的存储,并且会在会话结束时自动清除数据。

Vue 以插件的形式注册组件

在Vue中组件最常用的调用方式,是内部引用,如下形式

<template>
    <div>
        <CompLoading />
    </div>
<template>

<script>
import CompLoading from './CompLoading.vue'
export default {
    ......
    components {
        CompLoading
    }
    ......
}
</script>

这样做有不少劣势

  • 局部注册:普通组件创建方式需要手动注册组件,意味着组件只能在注册的作用域内使用
  • 管理不便:普通组件需要手动导入、注册后才能使用
  • 不适合大型项目

针对上述问题,这边介绍一种vue中通过插件创建组件的方式

插件创建组件

优点

  • 全局注册:通过插件创建的组件可以全局注册,意味着可以在项目中任何地方使用该组件,而不需要手动导入和注册
  • 方便管理:插件方式创建的组件可以集中管理,一个插件文件可以管理多个组件
  • 可扩展性强:可通过插件的选项来扩展其功能
  • 自动注册:当 使用Vue.use方法安装插件时,插件会自动调用install方法来注册组件和方法

代码示例

目录结构

- plugins
    - compLoading
        - CompLoading.vue
        - index.js

index.js

/**
 * 这里面包含两个组件
 * 1. CompLoading - 全局注册的组件,提供了一个基础的模版
 * 2. LocalLoading - 局部创建的组件,扩展了AppleLoading组件的功能
 */
import CompLoading from './CompLoading.vue'
export default {
  vm: null,
  // 安装插件到vue实例
  install (Vue) {
    // 全局注册CompLoading组件
    Vue.component('CompLoading', CompLoading)

    // 初始化一个标识,来跟踪loading组件是否显示
    Vue.prototype.$loadingShow = null

    // 定义一个方法(用来显示loading组件)
    Vue.prototype.$compLoading = function (text, options = {}) {
      // 如果loading组件没有显示,那么就显示它
      if (!Vue.prototype.$loadingShow) {
        // 创建一个新的Vue局部组件-LocalLoading(是CompLoading组件的一个子类或者扩展)
        const loadingTpl = Vue.extend({
          name: 'LocalLoading',
          data () {
            return {
              isShow: false
            }
          },
          render (h) {
            // CompLoading组件的属性
            const props = {
              text,
              isShow: this.isShow,
            }
            // 渲染CompLoading组件(使用CompLoading组件作为模版进行渲染)
            return h(CompLoading, { props })
          }
        })
        
        // 创建一个新的loadingTpl组件实例
        const loadingVM = new loadingTpl()
        // 将组件挂载到DOM
        this.vm = loadingVM.$mount()
        // 获取组件的DOM元素
        const el = this.vm.$el
        // 显示组件
        this.vm.isShow = true
        // 这是$loadingShow标识为true
        Vue.prototype.$loadingShow = true
        // 把生成的提示的dom插入body中
        document.body.appendChild(el)
      }
    }

    // 定义一个方法(用来隐藏loading组件)
    Vue.prototype.$loadingHide = function () {
      // 如果loading组件已经显示,那么就隐藏它
      if (Vue.prototype.$loadingShow) {
        // 从DOM中移除loading组件
        document.body.removeChild(this.vm.$el)
        // 销毁组件实例
        this.vm.$destroy()
        // 更新标识为null
        Vue.prototype.$loadingShow = null
      }
    }
  }
}

CompLoading.vue

<template>
  <div>
    <div v-if="isShow">
      <p>{{ text }}</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'CompLoading',
  props: {
    text: {
      type: String,
      default: ''
    },
    isShow: {
      type: Boolean,
      default: false
    }
  },
}
</script>

main.ts

import Vue from 'vue'
import compLoading from '@/plugins/compLoading/'

Vue.use(compLoading, {}) // 此时,已经调用了install方法。组件已经挂载了,但是props值都是默认的

使用场景

// vue2
this.$compLoading('加载中...')

// vue3
context.root.$compLoading('加载中...')