【JavaScript】封装自己的JavaScript公共工具函数,并上传到npm中 进行下载

js公共方法封装方式都有哪些

全局函数

function greet(name) {
  console.log("Hello, " + name + "!");
}

greet("Alice"); // 调用全局函数

对象字面量

var utils = {
  add: function(a, b) {
    return a + b;
  },
  subtract: function(a, b) {
    return a - b;
  }
};

console.log(utils.add(5, 3)); // 调用对象字面量中的方法

命名空间

var myApp = {};

myApp.utils = {
  multiply: function(a, b) {
    return a * b;
  },
  divide: function(a, b) {
    return a / b;
  }
};

console.log(myApp.utils.multiply(4, 2)); // 调用命名空间下的方法

模块化(使用 ES6 的模块化语法)

// math.js
export function square(x) {
  return x * x;
}

export function cube(x) {
  return x * x * x;
}

// main.js
import { square, cube } from './math.js';

console.log(square(5)); // 调用模块中的方法

上述四种有什么区别

全局函数:定义一个全局函数,可以在任何地方直接调用。这种方式最为简单,但是容易导致命名冲突,影响代码的可维护性

对象字面量:使用对象字面量(或称“JSON”)来封装公共方法,可以将多个方法组织在同一个对象中,便于管理和调用。这种方式相对于全局函数更为可维护,但是仍然存在命名冲突的问题

命名空间:使用命名空间来避免命名冲突。将所有相关的方法都放在同一个命名空间下,可以有效地减少全局变量的数量

模块化:使用模块化的方式来封装公共方法,可以将代码划分为多个模块,每个模块都有自己的作用域,可以避免命名冲突

JavaScript公共工具函数

// 命名空间封装法
var ACutils = {}
ACutils.verify = {
  /*
   * 验证手机号是否合格
   * true--说明合格
   */
  verifyPhoneNumber: function (phoneStr) {
    let myreg = /^[1][3,4,5,7,8,9][0-9]{9}$/
    if (!myreg.test(phoneStr)) {
      return false
    } else {
      return true
    }
  },
  /*
   * 验证身份证号是否合格
   * true--说明合格
   */
  verifyIdCard: function (idCardStr) {
    let idcardReg =
      /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/
    if (idcardReg.test(idCardStr)) {
      return true
    } else {
      return false
    }
  },
  /*
   * 验证邮箱是否合格
   * true--说明合格
   */
  verifyEmail: function (isEmailStr) {
    let isEmailReg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
    if (isEmailReg.test(isEmailStr)) {
      return true
    } else {
      return false
    }
  },
  /*
   * 验证密码格式是否符合规范
   * 密码由大小写字母 数字组成
   */
  verifyPassword: function (password) {
    const reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]+$/
    return reg.test(password)
  },
  /*
   * 验证用户名格式是否符合规范 规避敏感字
   * 可以由大小写字母 数字 汉字组成
   * sensitiveWords 是敏感字数组
   */
  verifyUsername: function (username, sensitiveWords) {
    const reg = /^[a-zA-Z0-9\u4e00-\u9fa5]+$/
    if (!reg.test(username)) {
      return false
    }
    for (let i = 0; i < sensitiveWords.length; i++) {
      if (username.includes(sensitiveWords[i])) {
        return false
      }
    }
    return true
  },
  /*
   *手机号码中间4位隐藏花号(*)显示
   * @param mobile 要处理的点好,字符串
   */
  hideMiddlePhone: function (mobile) {
    return mobile.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')
  }
}
ACutils.number = {
  /*
   * 数字四舍五入(保留n位小数)
   * @param number 要处理的数字
   * @param n 保留位数
   */
  roundNumber: function (number, n) {
    n = n ? parseInt(n) : 0
    if (n <= 0) return Math.round(number)
    number = Math.round(number * Math.pow(10, n)) / Math.pow(10, n)
    return number
  }
}
ACutils.string = {
  /*
   * 去除字符串空格
   * @param str 要处理的字符串
   * @param type 1:所有空格 2:前后空格 3:前空格 4:后空格
   */
  removeStrSpaces: function (str, type) {
    switch (type) {
      case 1:
        return str.replace(/\s+/g, '')
      case 2:
        return str.replace(/(^\s*)|(\s*$)/g, '')
      case 3:
        return str.replace(/(^\s*)/g, '')
      case 4:
        return str.replace(/(\s*$)/g, '')
      default:
        return str
    }
  }
}
ACutils.dom = {
  /*
   * 滚动到页面顶部
   *
   */
  scrollToTop: function () {
    const height = document.documentElement.scrollTop || document.body.scrollTop
    if (height > 0) {
      window.requestAnimationFrame(scrollToTop)
      window.scrollTo(0, height - height / 8)
    }
  }
}
ACutils.array = {
  /*
   * 数组去重
   *
   */
  removeDuplicates: function (arr) {
    let uniqueArr = []

    for (let i = 0; i < arr.length; i++) {
      if (uniqueArr.indexOf(arr[i]) === -1) {
        uniqueArr.push(arr[i])
      }
    }

    return uniqueArr
  },

  /*
   * 多维数组扁平化
   *
   */
  flattenArray: function (arr) {
    let flattened = []
    let _this = this
    for (let i = 0; i < arr.length; i++) {
      if (Array.isArray(arr[i])) {
        flattened = flattened.concat(_this.flattenArray(arr[i]))
      } else {
        flattened.push(arr[i])
      }
    }
    return flattened
  }
}
ACutils.obj = {
  /*
   * 引用类型深拷贝
   * 没有返回null
   */
  deepCopy: function (obj) {
    let _this = this
    if (obj === null || typeof obj !== 'object') {
      return obj
    }

    let copy = Array.isArray(obj) ? [] : {}

    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        copy[key] = _this.deepCopy(obj[key])
      }
    }

    return copy
  },
  /*
   * 将数组对象中的某一项属性提取出来,以数组展示
   * @param data 数组对象
   * @param propertyName 需要提取的属性
   */
  extractProperty: function (data, propertyName) {
    var propertyValues = []

    for (var i = 0; i < data.length; i++) {
      propertyValues.push(data[i][propertyName])
    }

    return propertyValues
  },
  /*
   * 将多个一维数组合并为数组对象
   * @param keys 包含属性键名的数组
   * @param propertyName 多个一维数组
   * @return 返回数组对象,如果空缺地方显示undefined
   */
  mergeArraysToObject: function (keys, ...arrays) {
    const length = Math.max(...arrays.map((arr) => arr.length))
    const result = []

    for (let i = 0; i < length; i++) {
      const obj = {}
      for (let j = 0; j < keys.length; j++) {
        obj[keys[j]] = arrays[j][i]
      }
      result.push(obj)
    }

    return result
  },
  /*
   * 根据数组对象的 number 类型属性进行排序
   * @property  排序的 number 类型属性名
   * @sortOrder 排序顺序,可选参数,默认为 'asc'(升序),可以设置为 'desc'(降序)
   */
  sortByNumberProperty: function (arr, property, sortOrder = 'asc') {
    if (sortOrder === 'asc') {
      arr.sort((a, b) => a[property] - b[property])
    } else if (sortOrder === 'desc') {
      arr.sort((a, b) => b[property] - a[property])
    }
    return arr
  },
  /*
   * 根据对象的日期属性进行排序
   * @property  排序的 number 类型属性名
   * @sortOrder 排序顺序,可选参数,默认为 'asc'(升序),可以设置为 'desc'(降序)
   */
  sortByDateProperty: function (arr, property, sortOrder = 'asc') {
    if (sortOrder === 'asc') {
      arr.sort((a, b) => new Date(a[property]) - new Date(b[property]))
    } else if (sortOrder === 'desc') {
      arr.sort((a, b) => new Date(b[property]) - new Date(a[property]))
    }
    return arr
  }
}
ACutils.time = {
  /*
   *获取当前时间,并根据传参“yy-mm-dd HH:MM:SS” 来确定返回时间格式
   * @param format 返回时间格式
   */
  getCurrentTime: function (format) {
    let currentDate = new Date()
    let year = currentDate.getFullYear()
    let month = (currentDate.getMonth() + 1).toString().padStart(2, '0')
    let day = currentDate.getDate().toString().padStart(2, '0')
    let hours = currentDate.getHours().toString().padStart(2, '0')
    let minutes = currentDate.getMinutes().toString().padStart(2, '0')
    let seconds = currentDate.getSeconds().toString().padStart(2, '0')

    let formattedTime = format
      .replace('yy', year)
      .replace('mm', month)
      .replace('dd', day)
      .replace('HH', hours)
      .replace('MM', minutes)
      .replace('SS', seconds)

    return formattedTime
  },
  /*
   *传入时间戳,并根据传参“yy-mm-dd HH:MM:SS 来确定返回时间格式
   * @param timestamp 时间戳
   * @param format 返回时间格式
   */
  formatTimestamp: function (timestamp, format) {
    let date = new Date(timestamp)
    let year = date.getFullYear()
    let month = (date.getMonth() + 1).toString().padStart(2, '0')
    let day = date.getDate().toString().padStart(2, '0')
    let hours = date.getHours().toString().padStart(2, '0')
    let minutes = date.getMinutes().toString().padStart(2, '0')
    let seconds = date.getSeconds().toString().padStart(2, '0')

    let formattedTime = format
      .replace('yy', year)
      .replace('mm', month)
      .replace('dd', day)
      .replace('HH', hours)
      .replace('MM', minutes)
      .replace('SS', seconds)

    return formattedTime
  },
  /*
   * 传入出生年月,返回年龄、并精准到月份
   *
   */
  computeAge_Month: function (birthDate) {
    let today = new Date()
    let birth = new Date(birthDate)

    let age = today.getFullYear() - birth.getFullYear()
    let monthDiff = today.getMonth() - birth.getMonth()
    if (
      monthDiff < 0 ||
      (monthDiff === 0 && today.getDate() < birth.getDate())
    ) {
      age--
      monthDiff = 12 - birth.getMonth() + today.getMonth()
    }

    let accurateAge = {
      years: age,
      months: monthDiff
    }

    return accurateAge
  },
  /**
   * 计算未来某一时间现在距的剩余时间
   *
   */
  formatRemainTime: function (endTime) {
    var startDate = new Date()
    var endDate = new Date(endTime)
    var t = endDate.getTime() - startDate.getTime()
    var d = 0,
      h = 0,
      m = 0,
      s = 0
    if (t >= 0) {
      d = Math.floor(t / 1000 / 3600 / 24)
      h = Math.floor((t / 1000 / 60 / 60) % 24)
      m = Math.floor((t / 1000 / 60) % 60)
      s = Math.floor((t / 1000) % 60)
    }
    return d + '天 ' + h + '小时 ' + m + '分钟 ' + s + '秒'
  }
}
ACutils.url = {
  /*
   * 获取url参数中的参数
   * @param url 要处理的字符串,../index.html?projId=xx&deviceId=xxx
   * 没有返回null
   */
  parseUrlParams: function (url) {
    let params = {}
    let urlParts = url.split('?')

    if (urlParts.length > 1) {
      let query = urlParts[1]
      let pairs = query.split('&')

      pairs.forEach(function (pair) {
        let keyValue = pair.split('=')
        let key = decodeURIComponent(keyValue[0])
        let value = decodeURIComponent(keyValue[1] || '')
        params[key] = value
      })
    }

    return params
  }
}
ACutils.ui = {
  /*
   * 弹窗提示框  水平垂直居中提示
   */
  showAlert: function (message, backgroundColor, textColor) {
    var alertBox = document.createElement('div')
    alertBox.textContent = message
    alertBox.style.position = 'fixed'
    alertBox.style.top = '50%'
    alertBox.style.left = '50%'
    alertBox.style.transform = 'translate(-50%, -50%)'
    alertBox.style.padding = '10px 20px'
    alertBox.style.borderRadius = '5px'
    alertBox.style.opacity = 0
    alertBox.style.transition = 'opacity 0.3s ease-in-out'
    alertBox.style.backgroundColor = backgroundColor
    alertBox.style.color = textColor

    document.body.appendChild(alertBox)

    setTimeout(function () {
      alertBox.style.opacity = 1
    }, 10)

    setTimeout(function () {
      alertBox.style.opacity = 0

      setTimeout(function () {
        alertBox.parentNode.removeChild(alertBox)
      }, 300)
    }, 2000)
  },
  /*
   * 确认框  水平垂直居中提示
   * callback执行的函数,传递true与false
   */
  showConfirm: function (message, backgroundColor, textColor, callback) {
    let confirmBox = document.createElement('div')
    confirmBox.className = 'confirm-box'
    confirmBox.style.backgroundColor = backgroundColor
    confirmBox.style.color = textColor
    confirmBox.style.position = 'fixed'
    confirmBox.style.top = '50%'
    confirmBox.style.left = '50%'
    confirmBox.style.transform = 'translate(-50%, -50%)'
    confirmBox.style.padding = '10px 20px'
    confirmBox.style.borderRadius = '5px'
    confirmBox.style.opacity = 0
    confirmBox.style.transition = 'opacity 0.3s ease-in-out'

    let messageElement = document.createElement('p')
    messageElement.textContent = message
    confirmBox.appendChild(messageElement)

    let confirmDiv = document.createElement('div')
    confirmDiv.style.display = 'flex'
    confirmDiv.style.justifyContent = 'space-around'

    let confirmButton = document.createElement('button')
    confirmButton.textContent = '确认'
    confirmButton.style.border = `1px solid ${textColor}`
    confirmButton.style.cursor = 'pointer'
    confirmButton.onclick = function () {
      hideConfirm(confirmBox)
      if (typeof callback === 'function') {
        callback(true)
      }
    }
    confirmDiv.appendChild(confirmButton)

    let cancelButton = document.createElement('button')
    cancelButton.textContent = '取消'
    cancelButton.style.border = `1px solid ${textColor}`
    cancelButton.style.cursor = 'pointer'
    cancelButton.onclick = function () {
      hideConfirm(confirmBox)
      if (typeof callback === 'function') {
        callback(false)
      }
    }
    confirmDiv.appendChild(cancelButton)
    confirmBox.appendChild(confirmDiv)

    document.body.appendChild(confirmBox)
    setTimeout(function () {
      confirmBox.style.opacity = 1
    }, 10)

    function hideConfirm(confirmBox) {
      confirmBox.style.opacity = 0
      setTimeout(function () {
        confirmBox.parentNode.removeChild(confirmBox)
      }, 300)
    }
  }
}

前端包常用包管理工具

npm 是 Node.js 官方提供的包管理工具,也是前端开发中最常用的包管理工具之一

cnpm 是对 npm 的一个淘宝镜像,旨在提供更快速、稳定的国内访问速度

nvm 是一个用于管理多个 Node.js 版本的工具。它允许开发人员在同一台计算机上安装和切换不同版本的 Node.js

上传到npm中

编写公共函数代码

确保公共函数已经封装好,并且在本地能够正常使用

创建 npm 账号

如果你还没有 npm 账号,需要先在 https://www.npmjs.com 上注册一个账号

初始化 npm 项目

在命令行中进入你的项目目录,运行以下命令来初始化 npm 项目:npm init

  • package name: 包名,你的包要发布的名称,通常是小写字母,不含空格。如果不想改变包名,直接按回车键即可
  • version: 初始版本号
  • description: 描述
  • entry point: 入口文件,该包的主文件名,即其他开发者通过 require 引入时加载的文件,默认为 index.js
  • test command: 测试命令,用于运行测试脚本的命令,没有回车就好
  • git repository: Git 仓库地址,没有回车就好
  • keywords: 关键词,用于描述该包的一些关键词,方便其他开发者搜索和发现你的包
  • author: 作者,你的名字或者你的公司名称
  • license: 许可证,授权许可证,标明你的包使用的开源许可证,回车就好

编写 README 文件

编写一个清晰明了的 README 文件,描述你的函数是做什么的,如何安装和使用。README 文件通常以 Markdown 格式编写

发布到 npm

npm login  // 如果之前没有登录过
npm publish

遇到的问题 

npm ERR! 403 403 Forbidden - PUT https://registry.npmmirror.com/-/user/org.couchdb.user:ac_from_hu_nan - [FORBIDDEN] Public registration is not allowedCjs>npm login

原因:是因为用的淘宝镜像,切换到官方的就行

解决:运行

npm config set registry https://registry.npmjs.org/

发布成功

下载自己的包

在目录中运行npm i xxx即可

更新自己的包 

npm login  
npm publish

每次修改后,记得更新 package.json 中的版本号,否则 npm publish 命令会失败

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/194588.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用opencv实现图片相似度检测

1.为什么学这个,我对图像处理非常感兴趣,我联想到海尔的指纹识别门锁是如何进行检测的,我在想不应该呀,单片机性能这么差,应该是使用了训练后的数据去检测图片的,如果我要实现草莓检测,知道它是不是草莓,我觉得单纯使用图片处理是不够的,我考虑过使用指纹模块来接触草莓从而实现…

芯片制程中温度的几种表示方法

在众多影响芯片制程的因素中&#xff0c;温度控制被视为一项至关重要的技术。温度是比较一种物质相对于另一种物质是冷还是热的衡量标准&#xff0c;它会影响到芯片的性能、可靠性以及最终产量。在不同的制程步骤中&#xff0c;温度扮演着各种各样的角色。但是在评价制程温度高…

振弦式轴力计和振弦采集仪组成的安全监测解决方案

振弦式轴力计和振弦采集仪组成的安全监测解决方案 振弦式轴力计和振弦采集仪是一种常用的结构安全监测工具&#xff0c;可以用于评估建筑物、桥梁、隧道或其他结构的结构健康状态和安全性能。这种监测方案较为先进、精确&#xff0c;并且能够监测长期的结构反应&#xff0c;因此…

Git指定分支或文件回退到指定版本

文章目录 一、分支回滚1.1、使用 git reset 命令1.2、使用 git revert 命令1.3、使用 git checkout 命令 二、文件回滚2.1、回滚未提交文件2.2、回滚已提交文件2.2.1、首先查看文件的历史版本2.2.2、找到你想要还原的版本2.2.3、将文件还原到你想要还原的版本2.2.4、提交代码 三…

便利高效双赢:无人机油气管道巡检全面升级

我国庞大的油气管道网络&#xff0c;包括原油、成品和天然气管道&#xff0c;因为地理区域广泛、建设年代久远、安全事故频发等现实因素&#xff0c;对管道的安全巡护与管理提出了更高的需求。在这一背景下&#xff0c;传统的人工巡护方式显然已经难以满足对高、精、准的要求。…

s_v_web_id或fp协议过签名,dy滑块

某音s_web_id或fp协议过签名 ‘h5_sdk_version’, ‘2.36.0’ "search_impr":{"entity_id":"1135137973613200"},"link_item_list":null,"user_permissions":null,"offline_info_list":null,"is_cf":…

计算机组成原理-页式存储器

文章目录 页式存储虚拟地址vs实地址页表&#xff1a;逻辑页->主存块号地址交换过程地址交换过程&#xff08;增加TLB&#xff09;总结 页式存储 把程序分散式地放到主存的不同块的地方 虚拟地址vs实地址 操作系统将逻辑地址映射到主存块中的物理地址&#xff0c;对应的物…

新疆大学与优艾智合机器人成立联合创新实验室

11月22日至24日&#xff0c;第五届中国工业互联网大赛新疆赛站决赛在新疆维吾尔自治区昌吉回族自治州昌吉市举行。在大赛中崭露头角的优秀解决方案&#xff0c;将为绿色工厂、绿色园区、绿色供应链等建设提供新的动能&#xff0c;促进工业绿色发展。 作为大赛的成果延伸&#…

unity UGUI中获取点击位置处的URL链接

需求是&#xff0c;我们在一个text组件中像写网页那样写入链接&#xff0c;然后点击这个链接&#xff0c;就能访问配置的网页啥的。比如&#xff1a; <a href"hello">链接文本</a></summary> 最终的效果如下&#xff1a; 图中&#xff0c;image区…

智能优化算法应用:基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蜻蜓算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

Docker Compose;docker-compose;docker compose

(一) Docker Compose | 菜鸟教程 --> --> --> -->

Spine深入学习———— 渲染

数据有了之后&#xff0c;就开始渲染 渲染相关 绘制顺序 骨架的绘制顺序就是一个插槽列表&#xff0c;在插槽列表中上方的附件在下方之上绘制&#xff0c;绘制顺序可以在层级树中的骨架下查看。 基础流程 渲染实现 以下按照cocos2dx的实现来 &#xff08;cocos2dx 3.7 spin…

内部类, Comparable接口, Comparator接口, Cloneable接口 ---java

目录 一. 内部类 1.1 静态内部类 1.2 实例内部类 1.3匿名内部类 二. 接口的使用实例 2.1 Comparable接口 2.2 Comparator接口 ---比较器 2.3 Cloneable接口 深拷贝浅拷贝 一. 内部类 当一个事物的内部&#xff0c;还有一个部分需要一个完整的结构进行描述&#xff0…

机器学习——支持向量机(SVM)

1.线性支持向量机 1.1数学模型 机器学习最终都是求解目标函数的最优问题&#xff1b; 一般都是讲问题转化为最小值来求解。 数学模型获得是一个不等式约束的最小化问题&#xff0c;求解时可通过构建拉格朗日函数求解。 1.2 拉格朗日函数及对偶问题求解 1.3 SMO算法求解 SMO算…

vue中的keep-alive详解与应用场景

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:vue-keep-alive 目录 一、Keep-alive 是什么 二、使用场景 三、原理分析 四、案例实现 activa…

虹科干货 | 适用于基于FPGA的网络设备的IEEE 1588透明时钟架构

导读&#xff1a;在基于FPGA的网络设备中&#xff0c;精确的时间同步至关重要。IEEE 1588标准定义的精确时间协议&#xff08;PTP&#xff09;为网络中的设备提供了纳秒级的时间同步。本文将介绍虹科提供的适用于基于FPGA的网络设备的IEEE 1588透明时钟&#xff08;TC&#xff…

flink源码分析之功能组件(三)-rpc组件

简介 本系列是flink源码分析的第二个系列,上一个《flink源码分析之集群与资源》分析集群与资源,本系列分析功能组件,kubeclient,rpc,心跳,高可用,slotpool,rest,metrics,future。 本文解释rpc组件,rpc组件用于个核心组件,包括作业管理器,资源管理器和任务管理器之…

uni-app 离线打包安卓Apk(小白上手)

场景&#xff1a; 在使用uni-app 开发apk时&#xff0c;使用云打包有次数限制。尤其对于测试阶段是无比难受的&#xff0c;通常是浪费打包次数进行打包或者通过usb 给测试机更新开发环境&#xff0c;但这都是无比漫长的过程 尤其有多个测试机真的是噩梦般的存在 下载离线打包示…

基于mpvue实现的cnode社区demo(附精选源码32套,涵盖商城团购等)

社区类目没有开放给个人开发者&#xff0c;所以没能上线。 预览 项目配置文件&#xff0c;更改appid {"description": "项目配置文件","setting": {"urlCheck": true,"es6": false,"postcss": false,"minif…

扫地机器人市场持续火爆,景联文科技数据采集标注方案助力扫地机器人智能化升级

随着消费者对智能家居和清洁卫生的需求增加&#xff0c;扫地机器人市场规模不断扩大。市场竞争也日益激烈&#xff0c;各品牌都在努力提升产品性能和服务质量&#xff0c;以获取更大的市场份额。 IDC的统计数据显示&#xff0c;今年双十一前两周&#xff08;2023年10月23日至20…