【问题宝典】前端开发过程中遇到的问题-解决方法

目录

代码

img标签正确的src地址写法

vue项目有这个图片但是突然开始报错

TypeError: Cannot read properties of undefined (reading 'setOption')

RangeError: Maximum call stack size exceeded

url路由找不到报错

时间格式互相转换

avue-crud-全选回调

js怎么把数组里的字符串转成数字0?

日期转换格式

深拷贝

表单清除数据和清除校验状态的方法

vue 监听事件(初始化数据不进行监听)

props传值为啥不能被修改

按钮点击弹出框确认与否 Popconfirm 气泡确认框

1、选取数组其中的某一个字段的数组、js 获取多个字段的对象数组中的某一些字段重新组成一个新的数组

输出代码

找到对应的值、找到对应的列:

鼠标到时显示小手

检测代码使用   可以改变字段名字

表单的label不显示方法(不推荐,因为dom结构会变化)

数组中的每个对象添加属性

在JavaScript数组中删除对象的特定字段(例如name字段)

el-form是可以没有标签的那种:

相加的方法!对我来说很新的东西

位与运算

vue组件对属性只watch一次的方法

判断变量是否有值

在 JavaScript 中使用 every() 方法检查数组中的所有值是否为真

报Maximum recursive updates exceeded错

跳转页面中组件支持接收入参实现方法:

css 使用变量(可复用变量尽量抽离为页面变量,易于统一维护)

前端问题

在 Web 系统中,当他人修改了设置后,你这边要获取最新设置,这是需要考虑的

是否需要考虑及原因

实现方式

1. 轮询机制

2. WebSocket

3. Server - Sent Events (SSE)

软件使用

vscode

代码

img标签正确的src地址写法

在Vue中,几种方式在标签内放入图片路径:

1、静态资源URL:如果你的图片在public文件夹下,可以直接通过静态资源路径引用。

<img src="/img/logo.png">

2、相对路径:如果图片在项目的src/assets文件夹下,可以使用相对路径。

<img src="./assets/logo.png">

3、绝对路径:直接使用图片的完整路径。

<img src="http://yourdomain.com/img/logo.png">

4、使用require方法:如果你想动态地引入图片,可以使用Vue的数据绑定和require方法。

<template>
  <img :src="imageUrl">
</template>
 
<script>
export default {
  data() {
    return {
      imageName: 'logo.png'
    }
  },
  computed: {
    imageUrl() {
      return require('@/assets/' + this.imageName);
    }
  }
}
</script>

5、使用Vue CLI项目中的assets模块:如果你使用Vue CLI创建的项目,可以利用webpack的assets模块。

<img src="<%= require('./assets/logo.png') %>">

请根据你的项目结构和需求选择合适的方法。

vue项目有这个图片但是突然开始报错

more.png:1 GET http://localhost:5500/src/public/img/XX/more.png 404 (Not found)

这个问题可能是由于以下几个原因造成的:

1 图片路径错误:可能是你的图片路径不正确,导致Vue项目无法找到这个图片文件。

2 文件缺失:图片文件可能已经被误删除或移动。

3 缓存问题:浏览器缓存了旧的配置,导致项目无法正确加载新的图片。

4 构建配置问题:可能是Vue项目的构建配置出现了问题,导致图片无法正确编译或输出。

解决方法:
检查
1.图片路径:确保你的图片路径与你在代码中引用的路径完全匹配。
2.检查文件存在:确认图片文件是否存在于项目的指定目录中。
3.清除缓存:尝试清除浏览器缓存,并重新加载页面。
4.检查构建配置:检查Vue项目的webpack或其他构建工具的配置文件,确保图片处理配置正确无误。
5.重新构建项目:删除node_modules目录和dist/build目录,然后重新运行npm install和npm run build或npm run serve。

TypeError: Cannot read properties of undefined (reading 'setOption')

报错解释:

这个错误表明你正在尝试调用一个undefined对象上的setOption方法。换句话说,你的代码中可能有一个变量,预期是一个包含setOption方法的对象,但实际上在你调用setOption方法的时候它是undefined。

解决方法:

  1. 确认变量在调用setOption方法前已经被正确赋值,并且确实是一个包含setOption方法的对象。
  2. 检查代码中是否有任何条件路径可能导致变量未被定义或赋值。
  3. 使用可选链(optional chaining)操作符来安全地调用setOption方法,例如:yourObject?.setOption()。这样如果yourObject是undefined,调用会被安全地忽略,而不是抛出错误。
  4. 如果setOption是一个高频调用且确定会存在,可以使用逻辑或操作符(||)提供一个默认值,例如:(yourObject || {}).setOption()。
  5. 使用调试工具,如浏览器的开发者工具,来检查setOption被调用时yourObject的值。

确保在调用setOption之前,相关对象已经被正确初始化和赋值。

RangeError: Maximum call stack size exceeded

vue 项目运行报错:RangeError: Maximum call stack size exceeded ; 意思是 堆栈溢出(内存溢出)

造成这种情况的原因有多个:

1、代码形成死循环,造成堆栈溢出 (递归)

如果不确定,可以做个输出,也有可能是调用的方法没有得到更新,导致一直调用同一个数值,也会造成递归

2、路由也有可能造成内存溢出

 3、引用组件名称和当前组件名称一样了

 快去给小姐姐点赞,受益匪浅了 ↓

原文地址:RangeError: Maximum call stack size exceeded-优快云博客

url路由找不到报错

[vite] Internal server error: Cannot read properties of undefined (reading ‘url‘)

这种情况的出现是因为新建了页面和路由,但是路由并不能读取到页面,此时我的项目是正在运行中的,需要把项目重启一下就可以了

来自 <[vite] Internal server error: Cannot read properties of undefined (reading ‘url‘)-优快云博客>

时间格式互相转换

中国标准时间、标准时间、时间戳时间格式转换 - 代码先锋网

// https://codeleading.com/article/61616611483/

shortcuts: [
              {
                text: '一小时内',
                value: this.setOclock(1),
              },
              {
                text: '三小时内',
                value: this.setOclock(3),
              },
              {
                text: '四小时内',
                value: this.setOclock(4),
              },
              {
                text: '今天',
                value: this.eighteenOclock(),
              },
              {
                text: '明天',
                value: this.eighteenOclock(1),
              },
              {
                text: '三天内',
                value: this.eighteenOclock(3),
              },
              {
                text: '一周内',
                value: this.eighteenOclock(7),
              },
            ],

            rules: [
              {
                validator: (rule, value, callback) => {
                  if (new Date(value).getTime() < Date.now()) {
                    callback(new Error('期望解决时间不能早于当前时间'));
                  } else {
                    callback();
                  }
                },
                trigger: 'change',
              },
            ],

setOclock(hours) {
      let now = new Date();
      let oclock = new Date(now).getTime();
      if (hours) {
        oclock = oclock + 3600 * 1000 * hours;
      }
      return oclock;
    },

avue-crud-全选回调

<avue-crud
      ref="crud"
	@select-all="selectAllChange"

selectAllChange(list){
      console.log('list',list)
      this.$refs.crud.toggleSelection(this.noSelList)
    },

js怎么把数组里的字符串转成数字0?

// 在JavaScript中,可以使用map()函数和Number构造函数将数组中的字符串转换为数字。如果字符串不能转换为有效的数字,它会被转换为0。
// 示例代码:
let stringsArray = ["1", "2", "three", "4", "5"];
 
let numbersArray = stringsArray.map(function(item) {
  return Number(item) || 0;
});
 
console.log(numbersArray); // 输出: [1, 2, 0, 4, 5]
//在这个例子中,map()函数遍历原数组stringsArray中的每个元素,尝试将其转换为数字,如果转换失败(比如"three"不能转成数字),Number(item) || 0的计算结果为0,因为||操作符的特性,如果左侧为假值(这里是转换失败的结果NaN),则返回右侧的值(即0)。

日期转换格式

// 给定的日期字符串  
let dateString = "2024-08-08";  
  
  // 将日期字符串转换为Date对象  
  let date = new Date(dateString);  
    
  // 验证日期字符串是否有效  
  if (isNaN(date.getTime())) {  
      console.error("Invalid date string");  
      return;  
  }  
    
  // 设置月份为当前月份减一(注意月份是从0开始的)  
  date.setMonth(date.getMonth() - 1);  
    
  // 如果日期小于1(即变为0),则需要将日期设置为上个月的最大天数  
  // 但由于JavaScript自动处理这个问题,所以这一步通常是可选的  
    
  // 将Date对象转换回日期字符串  
  let formattedDate = date.toISOString().split('T')[0]; // 使用ISO格式,只取日期部分  
    
  console.log(formattedDate); // 输出类似:2024-07-08

深拷贝

 // this.formModel = this.headDetail;
      this.formModel = Object.assign({}, this.headDetail); 
      this.formModel = { ...this.headDetail }; 
      // this.formModel 和 this.headDetail 是同一个对象的两个引用,而不是两个独立的对象。
      // 因此,对其中一个引用的修改会反映在另一个引用上。

// 如果你想要 this.formModel 和 this.headDetail 是两个独立的对象,
// 但初始时具有相同的属性值,你应该执行一个浅拷贝(shallow copy)或深拷贝(deep copy)。
// 浅拷贝只会复制对象的顶层属性及其引用,但不会递归地复制这些引用的内容。
// 深拷贝则会递归地复制对象的所有属性及其内容

表单清除数据和清除校验状态的方法

1 清除全部校验状态+数据

this.$refs.form.resetFields();

2 清除form的全部校验状态

this.$refs.form.clearValidate();

3,清除固定的字段的校验

const field = 'supplierName'; // 要清除校验的字段名

const rules = this.$refs.form.rules;

if (rules && rules[field]) {

  this.$refs.form.clearValidate(field);

}

原文链接:https://blog.youkuaiyun.com/maxiaole_z/article/details/136682101

vue 监听事件(初始化数据不进行监听)

//创建一个flag参数
data:{
  retrun{
    flag:false
  }
}
//flag为true进行下一步操作
watch: {
        Discount(newVal) {
            if (this.flag) {
 
            }
        },
//在数据更新完成之后调用 比如可在mounted() {},数据更改的函数中
this.$nextTick(() => {
     this.flag = true
       })

(步骤:

一、创建一个flag,初始值为false

二、监听时根据flag来判断是否进行下一步操纵

三、使用$nextTick,对flag再进行赋值为true

$nextTick是关键,作用是将回调延迟到下次DOM更新循环之后执行,就是说等改初始化完成之后再对监听时间放行,达到初始化时不对数据进行监听的作用。)      

原文链接: https://blog.youkuaiyun.com/weixin_62686026/article/details/128469423

props传值为啥不能被修改

在Vue框架中,子组件不应该直接修改通过props传递进来的值,原因如下:12

单向数据流:Vue遵循单向数据流的概念,这意味着数据只能从父组件流向子组件,而不能反向流动。这种设计有助于保持数据的一致性和可预测性,使得应用程序的状态管理更加清晰和易于维护。如果子组件能够修改props中的数据,那么将会破坏单向数据流的规则,导致数据流向变得难以追踪。

数据更新与追踪:为了保证数据的单向流动,便于对数据的追踪,当出现错误时可以迅速定位到错误发生的位置。所有的props都使得其父子组件之间形成了一个单向下行绑定:父级props的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致应用的数据流向难以理解。

组件的稳定性:每次父组件发生变更时,子组件中所有的props都会刷新为最新的值。这意味着你不应该在子组件内部改变props。如果你这样做了,Vue会在浏览器的控制台中发出警告。

避免副作用:直接修改props可能会导致不可预期的副作用,因为这样的修改可能会与父组件的预期状态发生冲突。相反,应该根据props的值使用数据或计算属性来响应式地更新子组件的状态。

总结来说,为了保持Vue应用的单向数据流、数据的一致性和可预测性、以及组件的稳定性,子组件不应该直接修改通过props传递进来的值。

menuForm 弹框自定义按钮未提供 done,loading 方法,导致表单处于禁用状态,无法进行下一步操作,此时调用以下方法即可

关闭弹框(done)等同于done()

// avue-crud 配置 ref = crud

this.$refs.crud.closeDialog()

取消禁用不关闭弹框(loading)等同于loading()

// avue-crud 配置 ref = crud

this.$refs.crud.$refs.dialogForm.$refs.tableForm.allDisabled = false

原文链接:https://blog.youkuaiyun.com/qq_45769187/article/details/126437408

按钮点击弹出框确认与否 Popconfirm 气泡确认框

<el-popconfirm title="是否确认删除?" ok-text="" cancel-text="" @confirm="handleDelete">

        <el-button

          v-if="permission.toolscheckdelete && createUser == userId"

          icon="el-icon-delete"

          class="top_option_btns"

          @click="handleDelete"

          >删除</el-button

        >

      </el-popconfirm>

1、选取数组其中的某一个字段的数组、js 获取多个字段的对象数组中的某一些字段重新组成一个新的数组

var user = [

         {

         id: 1,

         name: "李四"

     },

     {

         id: 2,

         name: "张三"

     },

     {

         id: 3,

         name: "李五"

     }

 ]

3种实现方法

1、var userName = Array.from(user,({name})=>name);

2、var userName = user.map((item)=>{

return item.name;

})

(好几个就是这样)

const newArr = arr.map(item => {

  return {

    name: item.name,

    age: item.age

  };

});

3、公共方法

function getAttrs(array,attr) {

    var arr = array.map((item)=>{

        return item[attr];

    })

    return arr;

}

console.log(getAttrs(user,'id')); //  [1, 2, 3]

console.log(getAttrs(user,'name')); //  ["李四", "张三", "李五"]

输出代码

console.log('onMounted', props);

找到对应的值、找到对应的列:

const column = this.findObject(this.option.column, 'parentId');

鼠标到时显示小手

cursor: pointer;

检测代码使用   可以改变字段名字

      newsList.value = [

        {

          busiType: 'om',

          id: '1788853115347730434',

        },

        {

          busiType: 'alarm',

          id: '1788853115347730434',

        },

        {

          busiType: 'overhaul',

          id: '1788853115347730434',

        },

        {

          busiType: 'security',

          id: '1788853115347730434',

        },

        {

          busiType: 'equipment',

          id: '1788853115347730434',

        },

      ];

表单的label不显示方法(不推荐,因为dom结构会变化)

{

          label: '基础信息',

          span: 12,

          row: true,

          prop: 'baseInfo',

        },

<template #baseInfo="{}">

        基础信息

      </template>

::v-deep .el-col:first-of-type  div.el-form-item__label{  

  display: none;

}

就可以变成:

 

展示信息的表单里面最好把他们换成折叠面板让他们无法折叠并且隐藏下边框和箭头

数组中的每个对象添加属性

let arr = [

{'name': 'aa', 'age': 10},

{'name': 'bb', 'age': 12}

]

let newArr = []

arr.map((item, index) => {

  newArr.push(

    Object.assign(item, { id: index} )

  )

})

console.log('newArr', newArr)

// [ {name: "aa", age: 10, id: 0},{name: "bb", age: 12, id: 1}]

在JavaScript数组中删除对象的特定字段(例如name字段)

let array = [

  { id: 1, name: 'Alice', age: 25 },

  { id: 2, name: 'Bob', age: 30 },

  { id: 3, name: 'Charlie', age: 28 }

];

let newArray = array.map(item => {

  let { name, ...rest } = item;

  return rest;

});

console.log(newArray);

例子:

let Data = this.ruleForms.items.map(item => {

          if (this.userId) {

            let { ref, ...rest } = item;

            return rest;

          } else {

            let { ref, userId, ...rest } = item;

            return rest;

          }

        });

el-form是可以没有标签的那种:

<el-form-item>// 一般是<el-form-item label="人员类别" prop="rosterType"> label="人员类别"就不会显示标签部分并且这样的方法没有冒号

          <el-input

            v-model="form.attributeValues"

            placeholder="请输入属性值"

            style="width: 15vw"

          ></el-input>

        </el-form-item>

示意图:

 

相加的方法!对我来说很新的东西

用户类别的一个1,2,4相加的逻辑:

handleAcctTypeChange(val){

      if(val){

        console.log('val.split(",")',val.split(","))

        console.log('val.split(",")',val.split(",").map(Number))

        console.log('val.split(",")',val.split(",").map(Number).reduce((acc, curr) => acc + curr, 0))

        this.form.acctType = val.split(",").map(Number).reduce((acc, curr) => acc + curr, 0);

      }else{

        this.form.acctType = null

      }

    },

这段代码是JavaScript中的一个表达式,它对一个字符串val进行了一系列操作,并最后计算出一个数字的总和。下面是逐步的解释:

  1. val.split(","):
  • split(",") 是一个字符串方法,它将字符串val按照逗号,分割成一个数组。例如,如果val是"1,2,3,4",那么val.split(",")的结果就是["1", "2", "3", "4"]。
  1. .map(Number):
  • map 是一个数组方法,它遍历数组的每个元素,并对每个元素执行一个函数。在这里,我们使用了Number作为一个函数(其实是一个构造函数),它尝试将数组的每个元素(即字符串)转换为一个数字。所以,如果之前的数组是["1", "2", "3", "4"],那么.map(Number)之后的结果就是[1, 2, 3, 4]。
  1. .reduce((acc, curr) => acc + curr, 0):
  • reduce 是另一个数组方法,它接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。
  • 在这个例子中,累加器函数(acc, curr) => acc + curr接收两个参数:累加器累加的值acc和当前元素curr。这个函数将acc和curr相加,并返回新的累加值。
  • 初始累加值(第二个参数)是0,所以开始时的累加值是0。
  • 所以,如果之前的数组是[1, 2, 3, 4],那么.reduce((acc, curr) => acc + curr, 0)的结果就是1 + 2 + 3 + 4 = 10。

综合上述步骤,acctType = val.split(",").map(Number).reduce((acc, curr) => acc + curr, 0); 这行代码的功能是:将字符串val(预期是逗号分隔的数字)转换为一个数字数组,并将这些数字相加,最后的结果存储在变量acctType中。注意:变量名acctType可能不是一个描述性很强的名字,因为它实际上存储的是一个数字的总和,而不是账户类型。

位与运算

位与运算(Bitwise AND)是计算机中一种基本的位运算,它直接对整数的二进制位进行操作。位与运算的规则很简单:对于每一个位,只有当两个操作数的相应位都为1时,结果的位才为1;否则为0。

在大多数编程语言中,位与运算使用&符号表示。下面是一个简单的例子,演示了如何使用位与运算:

假设我们有两个8位二进制数:

A = 10101010(二进制) = 170(十进制)

B = 11000100(二进制) = 196(十进制)

执行位与运算 A & B:

10101010

& 11000100

= 10000000(二进制) = 128(十进制)

可以看到,只有A和B都为1的位(即第一个和第四个位)在结果中才为1,其他位都为0。

位与运算在编程中有许多用途,例如:

  1. 检查特定位是否为1:通过与一个只有一个位为1的二进制数进行位与运算,可以检查另一个数的相应位是否为1。例如,要检查一个数的第二位是否为1,可以与二进制数00000010(十进制中的2)进行位与运算。
  2. 清零特定位:通过与一个除了要清零的位之外都为1的二进制数进行位与运算,可以将一个数的特定位清零。例如,要清零一个数的第二位,可以与二进制数11111101(十进制中的253)进行位与运算。
  3. 掩码操作:在网络编程和硬件编程中,位与运算经常用于掩码操作,以选择或屏蔽特定的位。
  4. 优化性能:在某些情况下,使用位与运算可以比使用其他运算更快,因为它直接在硬件级别上操作二进制位。但是,这种优化通常只在处理大量数据或需要高性能的场景中才显著。

注意:位与运算的结果是一个整数,其二进制表示是两个操作数二进制表示的位与结果。

vue组件对属性只watch一次的方法

mounted() {

    const unwatch = this.$watch('data', function (newValue, oldValue) {

      this.ruleForms.items = this.data;

      this.ruleForms.items.forEach((item, index) => {

        item.ref = 'Form' + index;

      });

      unwatch();

    });

  },

判断变量是否有值

var node;

……

判断 node 是否有值,是否为 undefine,是否 null,直接使用两个!!,否定之否定:

if (!!node){

....

}else{

....

}

这个条件判断一定会返回  true / false,以前不知道这个用法,现在记下来备查。

类似情况,有些 JS 库使用如下结构包装起来:

!function ($) {

$(function(){ 

})

}(window.jQuery)

也是在定义执行函数时,返回 true/false,而不是 undefined。这里不详述了,可以参见:

What does !function ($) { $(function(){ }) }(window.jQuery) do? - Stack Overflow

来自 <JS 变量是否有值的判断 - 明净 - 博客园>

在 JavaScript 中使用 every() 方法检查数组中的所有值是否为真

every() 方法是 JavaScript 提供的内置方法,用于检查数组内的所有元素是否都通过提供的函数执行的条件/标准。 根据函数,它返回 true 或 false 布尔值。

const inputArray  = [true, true, true, true, true, false, true, true, true];

console.log(inputArray.every(x => x === true));输出false

报Maximum recursive updates exceeded错

递归

死循环

可能情况:

1、比较复杂的、可能是自己写的this。refs。。。的validate校验方法   出错
2、avue表格的表单的按钮用form为参数用它但是改变了,就会报错 解决方法一切从表格表单的数据(很有可能是响应式的、或者和别的是没有关联)一律深拷贝 let params=this.deepClone(row)

跳转页面中组件支持接收入参实现方法:

跳转router。push 传参数给页面、页面接收,给组件参数,组件搜索,渲染搜索出来的数据。

测试正常跳转、正常接收、搜索在各个情况下都正常、渲染数据正常。

这个接收的方式:

1. 使用query参数(适用于Vue Router的history模式或hash模式)

如果你的Vue应用使用了Vue Router,你可以通过URL的查询参数(query)来传递数据。在源页面,你可以使用router.push或router.replace方法来导航到目标页面,并附加查询参数。

this.$router.push({ path: '/target-page', query: { id: id } });

data() { 

    return { 

      // 假设你要根据id来获取数据 

      id: this.$route.query.id, 

      // 你可以根据id去请求数据,并存储在某个数据属性中 

      // 例如:dataFetched: null, 

    }; 

  },

2. 使用Vuex(适用于状态管理)

如果你的应用较为复杂,涉及到多个组件之间的状态共享,那么使用Vuex来管理状态可能是一个更好的选择。

在源页面(导航发起方):

你可以将需要传递的数据存储在Vuex的store中。

// 假设你有一个mutation来设置id 

this.$store.commit('setId', 123); 

// 然后导航到目标页面 

this.$router.push('/target-page');

在目标页面(接收方):

你可以通过访问Vuex的store来获取这个数据。

exportdefault{ 

computed: { 

id() { 

returnthis.$store.state.id; 

}, 

}, 

// 类似于上面,使用id去请求数据 

};

3. 使用props(适用于动态路由匹配)

如果你的页面跳转是基于某个动态路由(例如,/user/:id),并且你希望根据这个动态部分来渲染页面,那么你可以使用Vue Router的动态路由匹配功能,并通过props将参数传递给组件。

Vue Router配置:

path: '/user/:id', 

component: User, 

props: true, // 或者使用函数来映射props 

}

User组件:

exportdefault{ 

props: ['id'], 

// 使用id去请求数据 

};

在这种情况下,当路由变化时(例如,从/user/123导航到/user/456),Vue Router会自动将id作为props传递给User组件。

选择哪种方法取决于你的具体需求,包括你的应用架构、数据流的复杂性以及你希望如何管理状态。

  • 单独写在router写一个页面当分析详情页面,可以自己设置页面名、

css 使用变量(可复用变量尽量抽离为页面变量,易于统一维护)

.container {

    $height: 50px;

    cursor: pointer;

    display: inline-block;

    width: $height;

    height: $height;

    line-height: $height;
  }

分钟数的格式化函数

function convertMinutes(minutes) {
  let days = Math.floor(minutes / (24 * 60))
  minutes %= 24 * 60
  let hours = Math.floor(minutes / 60)
  minutes %= 60
  let dayText = `${days ? days + '天' : ''}`
  let hourText = `${
    hours ? (hours < 10 ? '0' + hours : hours) + '小时' : days && minutes ? '0小时' : ''
  }`
  // 使用模板字符串来格式化输出;如果天数、小时数或分钟数为个位数,前面加上0以保持格式一致
  return `${dayText}${hourText}${
    minutes ? (minutes < 10 ? '0' + minutes : minutes) + '分钟' : ''
  }`.trim()
}
console.log('1100', convertMinutes(1100))// 18小时20分钟
console.log(convertMinutes(1441))// 1天0小时01分钟

小时的格式化函数

function convertHours(hours) {
  let days = Math.floor(hours / 24) // 计算天数
  let remainingHours = round(hours % 24, 2) // 计算剩余的小时数,四舍五入到小数点后两位

  // 使用模板字符串来格式化输出
  // 注意:如果天数或小时数为个位数,前面可以加上0以保持格式一致(可选)
  if (days > 0) {
    // 如果有天数,则返回 "X天Y小时"
    return `${days}${days > 1 ? '天' : '天'}${
      remainingHours
        ? '' + (remainingHours < 10 ? '0' + remainingHours : remainingHours) + '小时'
        : ''
    }`
  } else {
    // 如果没有天数(即小于24小时),则只返回小时数
    // 这里也可以决定是否在小时数前加'0'以保持格式,但通常小于10的小时数前不加'0'也是可以接受的
    return `${remainingHours}${remainingHours < 10 ? '小时' : '小时'}`
  }

  // 注意:上面的逻辑中,如果remainingHours为0,则只返回天数部分,这通常是期望的行为
  // 但如果你想要在所有情况下都至少显示一个时间单位(即使为0),可以稍作调整
}

前端问题

在 Web 系统中,当他人修改了设置后,你这边要获取最新设置,这是需要考虑的

是否需要考虑及原因

 

需要考虑获取最新设置,主要原因如下:

  • 数据一致性:保证你看到和使用的设置与系统中最新的设置一致,避免因使用旧设置而产生错误或不一致的操作结果。
  • 用户体验:及时获取最新设置可以让你实时感知系统的变化,获得更好的使用体验。

实现方式

1. 轮询机制
  • 原理:客户端按照一定的时间间隔向服务器发送请求,检查设置是否有更新。
  • 示例代码(使用 JavaScript 和 jQuery)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>轮询获取设置</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        function fetchSettings() {
            $.ajax({
                url: '/api/getSettings', // 替换为实际的获取设置的 API 地址
                method: 'GET',
                success: function (response) {
                    // 处理获取到的最新设置
                    console.log('最新设置:', response);
                },
                error: function (error) {
                    console.error('获取设置时出错:', error);
                }
            });
        }

        // 每 5 秒执行一次轮询
        setInterval(fetchSettings, 5000);
    </script>
</head>

<body>

</body>

</html>
 
  • 优缺点:实现简单,但会增加服务器负担,且不能实时获取更新,存在一定延迟。
2. WebSocket
  • 原理:建立客户端和服务器之间的持久连接,服务器在设置更新时主动向客户端推送最新设置。
  • 示例代码(使用 JavaScript)
 
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket 获取设置</title>
    <script>
        const socket = new WebSocket('ws://your-server-url'); // 替换为实际的 WebSocket 服务器地址

        socket.onopen = function () {
            console.log('WebSocket 连接已建立');
        };

        socket.onmessage = function (event) {
            const settings = JSON.parse(event.data);
            // 处理获取到的最新设置
            console.log('最新设置:', settings);
        };

        socket.onclose = function () {
            console.log('WebSocket 连接已关闭');
        };

        socket.onerror = function (error) {
            console.error('WebSocket 发生错误:', error);
        };
    </script>
</head>

<body>

</body>

</html>
 
  • 优缺点:实时性好,服务器压力小,但实现相对复杂,需要服务器端支持 WebSocket。
3. Server - Sent Events (SSE)
  • 原理:服务器向客户端单向发送实时更新,客户端只需建立一个 HTTP 连接,服务器可以随时向客户端发送新的数据。
  • 示例代码(使用 JavaScript)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE 获取设置</title>
    <script>
        const eventSource = new EventSource('/api/settingsStream'); // 替换为实际的 SSE 接口地址

        eventSource.onmessage = function (event) {
            const settings = JSON.parse(event.data);
            // 处理获取到的最新设置
            console.log('最新设置:', settings);
        };

        eventSource.onerror = function (error) {
            console.error('SSE 发生错误:', error);
            eventSource.close();
        };
    </script>
</head>

<body>

</body>

</html>
  • 优缺点:实现相对简单,实时性较好,但只支持服务器向客户端的单向通信。

软件使用

vscode

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值