前端使用elementui开发后台管理系统的常用功能(持续更新)

前言:本次的文章完全是自己开发中遇到的一些问题,经过不断的修改终于完成的一些功能,当个快捷的查看手册吧~

elementui开发后台管理系统常用功能

高级筛选的封装

功能描述:数据使用的若依的字典,或者是自定义数据,可以点击每个选项进行选择,取消选择,也可以在已选择进行清除和单个删除

javascript 复制代码
const officeConfig = {
  title: "高级检索",
  isShowHeader: false,
  configList: [
    {
      label: "人员性质", // 显示的名称
      data: [], // 显示的名称
      type: "dict", // 类型:默认 字典 输入框
      dict: "personnel_nature", // 如果是字典需要写
      isMultiple: true, // 是不是多选
      field: "staffType" // 需要给后端传递的字段名称
    },
    {
      label: "年龄",
      type: "default",
      data: [
        {
          label: "20岁以下",
          value: "0 and 20",
        },
        {
          label: "20-30",
          value: "20 and 30",
        },
      ],
      dict: "",
      isMultiple: false,
      field: "age"
    },
    {
      label: "请选择",
      type: "input",
      data: [
        {field: "staffName", placeholder: "请填写"},
        {field: "dutyName", placeholder: "请填写"},
        {field: "deptName", placeholder: "请填写"},
      ],
      dict: "",
      isMultiple: false,
      field: ""
    },
  ],
  showTable: false,
  tableConfig: {
  	// 表格配置
    propList: [
      { prop: 'inFloor', label: '所属楼层', minWidth: '100'},
    ],
    showSelectColumn: false,
    showIndexColumn: true,
  }
}


const queryForm = {}
officeConfig.configList.forEach(item => {
  if (item.type === "input") {
    item.data.forEach(val => {
      queryForm[val.field] = ""
    })
  } else {
    queryForm[item.field] = []
  }
})

export {
  officeConfig,
  queryForm
}
html 复制代码
// configList 是在外部进行单独配置的

<div class="query-wrap">
  <el-form :model="queryForm" ref="ruleForm" label-width="100px" class="demo-ruleForm">
    <el-form-item v-for="(item, index) in configList" :key="index" :label="item.label">
      <template v-if="item.type === 'dict'">
        <el-checkbox-group v-model="queryForm[`${item.field}`]">
          <el-checkbox 
            class="radio-btn" 
            v-for="(dict, index) in dict.type[item.dict]" 
            :key="index" 
            :label="dict.value"
            @change="handleCheckedItemChange(item, dict)">{{dict.label}}</el-checkbox>
        </el-checkbox-group>
      </template>
      <template v-if="item.type === 'default'">
        <el-checkbox-group v-model="queryForm[`${item.field}`]">
          <el-checkbox 
            class="radio-btn" 
            v-for="(dict, index) in item.data" 
            :key="index" 
            :label="dict.value"
            @change="handleCheckedItemChange(item, dict)">{{dict.label}}</el-checkbox>
        </el-checkbox-group>
      </template>
      <template v-if="item.type === 'input'">
		  <div style="display: flex;">
		    <template v-for="(dict, index) in item.data">
		      <el-input v-model="queryForm[`${dict.field}`]" :key="index" :placeholder="dict.placeholder" clearable></el-input>
		    </template>
		  </div>
		</template>
    </el-form-item>
    <el-form-item label="请选择">
    </el-form-item>
  </el-form>
  <div class="select-row">
    <div>
      <div class="select-text">已选条件</div>
      <div class="select-wrap">
        <div class="item" v-for="(item, index) in selectItem" :key="index">
          {{item.label}}
          <i class="el-icon-close" style="margin-left: 5px; cursor: pointer;" @click="handleRemoveItem(item)"></i>
        </div>
      </div>
      <el-tooltip style="margin-right: 15px;" effect="dark" content="查询" placement="top">
        <el-button icon="el-icon-search" circle @click="handleQuerySuccess"></el-button>
      </el-tooltip>
      <el-tooltip style="margin-right: 15px;" effect="dark" content="清除选项" placement="top">
        <el-button icon="el-icon-close" circle @click="clearSelectHandle"></el-button>
      </el-tooltip>
    </div>
  </div>
</div>

<script>
export default {
  props: {
    title: {
      type: String,
    },
    isShowHeader: {
      type: Boolean,
      default: true
    },
    configList: {
      type: Array,
      default: () => ([])
    },
    queryForm: {
      type: Object,
      default: () => ({})
    },
    showTable: {
      type: Boolean,
      default: true
    },
    tableData: {
      type: Array,
      default: () => ([])
    },
    tableConfig: {
      type: Object,
      default: () => ({})
    },
    loading: {
      type: Boolean,
      default: false
    },
    tableTotal: {
      type: Number
    },
  },
  dicts: [
    你使用到的字段字段
  ],
  data() {
    return {
      value: "",
      active: false,
      selectItem: [],
    };
  },
  methods: {
  	// 点击选择的时候进行一个数据的保存,再次点击删除
    handleCheckedItemChange(item, data) {
      console.log(item, data);
      const arr = this.selectItem.filter(selectItem => {
        if ((selectItem.value == data.value) && (selectItem.label == data.label)) {
          return selectItem
        }
      })

      if (!arr.length) {
        this.selectItem.push({label: data.label, value: data.value, field: item.field})
      } else {
        const index = this.selectItem.findIndex((itemIndex) => (itemIndex.value == data.value)&&(itemIndex.label == data.label) )
        this.selectItem.splice(index, 1)
      }
    },
    handleQuerySuccess() {
      this.$emit("querySuccess")
    },
    // 删除item
    handleRemoveItem(item) {
      const index = this.selectItem.findIndex((itemIndex) => (itemIndex.value == item.value)&&(itemIndex.label == item.label))
      this.selectItem.splice(index, 1)
      this.$emit("removeItem", item)

      if (!this.selectItem.length) {
        this.clearSelectHandle()
      }
    },
    // 清空所有选项
    clearSelectHandle() {
      this.selectItem = []
      this.$emit("clearSelectQuery")
    },
    handlePutAway() {
      this.$emit("putAway")
    },
  },
};  
</script>

<style lang="scss" scoped>
::v-deep {
  .query-wrap {
    padding: 10px 0;
    margin-bottom: 20px;
    background: #FFFFFF;
    box-shadow: inset 0px 1px 4px 0px #ABC7FF;
    border-radius: 0px 0px 0px 0px;
    .el-form-item__label {
      font-size: 14px;
      font-weight: 600;
      color: #142952;
      margin-right: 10px;
    }
    .el-form-item {
      margin-bottom: 15px;
    }
    .el-form-item__content {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      .el-radio__input {
        display: none;
      }
    }
    .radio-btn {
      margin-right: 20px;
      background: #EFF4FF;
      border-radius: 2px;
      font-size: 12px;
      color: #3B558A;
      padding: 0 25px;
      height: 30px;
      line-height: 30px;
      .el-radio__label {
        font-size: 12px;
        padding-left: 0;
      }
      &.is-checked {
        background: linear-gradient(270deg, #328EF4 0%, #0468FD 100%);
        color: #FFFFFF !important;
      }
      .el-checkbox__input {
        display: none;
      }
      .el-checkbox__label {
        padding-left: 0;
      }
    }
    .el-checkbox__input.is-checked + .el-checkbox__label {
      color: #FFFFFF !important;
    }
  }
}
.query-btn {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding: 20px;
  box-sizing: border-box;
}
.select-row {
  display: flex;
  align-items: center;
  justify-content: space-between;

  > div:first-child {
    display: flex;
    align-items: center;
  }
  
  .select-text {
    height: 36px;
    line-height: 36px;
    width: 100px;
    padding-right: 12px;
    box-sizing: border-box;
    text-align: right;
    margin-right: 10px;
    font-size: 14px;
    font-weight: 600;
    color: #142952;
  }
  .select-wrap {
    display: flex;
    flex-wrap: wrap;
    width: 1054px;
    > .item {
      background: #EFF4FF;
      border-radius: 2px;
      border: 1px dotted #BCD2FF;
      margin-right: 20px;
      height: 30px;
      line-height: 30px;
      padding: 0 16px;
      box-sizing: border-box;
      margin-bottom: 0;
      font-size: 14px;
      color: #0568FD;
      margin-bottom: 5px;
    }
  }
  .select-clear {
    font-size: 12px;
    color: #0079FE;
    cursor: pointer;
  }
}
</style>

使用:

html 复制代码
<height-search
  v-bind="config"
  :query-form="advanQueryForm"
  @querySuccess="cpnHandleQuerySuccess"
  @removeItem="handleRemoveItem"
  @clearSelectQuery="clearSelectQuery"
  @putAway="handlePutAway"
></height-search>
<script>
import { officeConfig, queryForm } from "./config";
import HeightSearch from "./HeightSearch.vue";

export default {
  name: "UserRegister",
  dicts: ["sys_normal_disable", "sys_user_sex"],
  components: { HeightSearch },
  data() {
    return {
      // 高级查询
      config: officeConfig,
      advanQueryForm: {},
      // 遮罩层
      queryTotal: 0,
      // 个人信息登记
      personInfoList: [],
    };
  },
  watch: {
    // 根据名称筛选机构树
    deptName(val) {
      this.$refs.tree.filter(val);
    },
  },
  created() {
    this.advanQueryForm = { ...queryForm, pageNum: 1, pageSize: 10 };
    this.handleQuerySuccess();
  },
  methods: {
    highSearchHandle() {
      this.handleQuerySuccess();
    },
    // 高级查询
    handleQuerySuccess() {
      // this.loading = true;
      const obj = { ...this.advanQueryForm };
      delete obj.pageNum;
      delete obj.pageSize;
      getListByConditions(this.advanQueryForm.pageNum, obj).then((response) => {
        this.personInfoList = response.rows;
        this.queryTotal = response.total;
      });
    },
    cpnHandleQuerySuccess() {
      this.advanQueryForm.pageNum = 1;
      this.handleQuerySuccess();
    },
    handleRemoveItem(item) {
      let arr = [...this.advanQueryForm[item.field]];
      let newArr = arr.filter((originItem) => originItem != item.value);
      this.advanQueryForm[item.field] = newArr;
    },
    clearSelectQuery() {
      this.advanQueryForm = { ...queryForm, pageNum: 1, pageSize: 10 };
      this.handleQuerySuccess();
    },
    handlePutAway() {
      this.advanQueryForm = { ...queryForm, pageNum: 1, pageSize: 10 };
    },
    // 查看信息
    handleSee(row) {
      this.$router.push({ name: "seeInfo", query: { id: row.staffId } });
    },
  },
};
</script>

elementui的表格

  • @selection-change 表格前面的select选择
  • :show-overflow-tooltip="true" 表格显示内容非常多,可以...省略
  • slot-scope="scope" 如果相对内容进行自定义展示可以使用默认插槽
  • 序号我们需求是分页序号要递增
html 复制代码
<el-table v-loading="loading" :data="绑定data数据-数组类型" @selection-change="handleSelectionChange">
  <el-table-column type="selection" width="55" align="center" />
  <el-table-column label="序号" type="index" width="50" align="center">
    <template slot-scope="scope">
      <span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
    </template>
  </el-table-column>
  <el-table-column label="想要展示的字段" align="center" prop="staffName" />
  <el-table-column label="申请原因" align="center" prop="applyReason" :show-overflow-tooltip="true" />
  <el-table-column label="申请时段" align="center" prop="endTime" width="180">
    <template slot-scope="scope">
      <span>{{ scope.row.startTime }}</span>
    </template>
  </el-table-column>
  <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="240" fixed="right">
    <template slot-scope="scope">
      <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
      <el-button size="mini" type="text" icon="el-icon-tickets" @click="handleDetail(scope.row)">详情</el-button>
      <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
    </template>
  </el-table-column>
</el-table>

elementui的表格实现跨页多选+回显

  • officeBuildingList 绑定的表格数据
  • @selection-change="handleOfficeSelect" 选择的方法
  • :row-key="getKey" 唯一标识
  • :reserve-selection="true"
javascript 复制代码
<el-table class="my-table" :data="officeBuildingList" @selection-change="handleOfficeSelect" ref="trainCourseTable" :row-key="getKey">
  <el-table-column type="selection" width="55" align="center" :reserve-selection="true" />
  <el-table-column label="数据" align="center" prop="字段" width="120" />
</el-table>

methods: {
	// 编辑情况回显数据:
	// 1. 因为是分页,简单做法就是一开始在create中调用获取全部的数据 pageSize:9999
	listOfficeBuilding({pageNum: 1,pageSize: 9999}).then((res) => {
		// 拿到form表单字段中的数据,在所有的数据中筛选
	  if (this.form.字段名称) {
	    const arr = this.form.字段名称.split(",")
	    res.rows.forEach(item => {
	      if (arr.includes(item.字段名称) && !this.suppliesMultipleList.includes(item)) {
	        this.suppliesMultipleList.push(item)
	      }
	    })
	  }
	});
	// 2. 打开弹窗调用接口获取表格数据,判断有字段并且是编辑状态才需要回显
	if (this.form.字段名称 && this.form.id) {
    this.$nextTick(() => {
    	// 把筛选好的
      this.suppliesMultipleList.forEach(row => {
        this.$refs.trainCourseTable.toggleRowSelection(row, true)
      })
    })
  }
}
// 点击表格前的复选框保存数据
handleOfficeSelect(val) {
  this.suppliesMultipleList = val
},
getKey(row) {
  return row.id;
},

elementui的表单

elementui的日历

javascript 复制代码
<el-calendar v-model="calendarValue">
  <template slot="dateCell" slot-scope="{date, data}">
    <div class="date">
      <div class="left">
        <span class="date-day">{{data.day.split('-')[2]}}</span>
        <span class="date-lunar">{{getClearList(data.day).lunar}}</span>
        <template v-for="item in workDateArr">
          <span class="rest-day" v-if="(item.status == '2') && (data.day == item.workDate)">放假</span>
          <span class="working-day" v-if="(item.status == '1') && (data.day == item.workDate)">班</span>
        </template>
      </div>
      <div class="date-festival">{{getClearList(data.day).festival}}</div>
    </div>
    <div style="height: 98px; overflow: hidden;">
      <template v-for="(item, index) in myScheduleCalendarPlanList">
        <div
          class="info"
          :style="{'background': item.color}"
          v-if="(new Date(data.day).valueOf()) >= (new Date(item.startTime).valueOf()) && (new Date(data.day).valueOf()) <= (new Date(item.endTime).valueOf())"
          @click="handleDetail(item.id)"
        >
          <i class="el-icon-time" style="margin: 0px 5px;"></i>
          <span class="text-area">{{item.eventTitle}}</span>
        </div>
      </template>
    </div>
    <div class="date-add" @click="myCalendarMore(data)">
      <div>查看全部</div>
    </div>
  </template>
</el-calendar>

这个是缩小以后的效果,为了截取全部,点击日期可以切换。我们这里的放假上班在系统有菜单进行单独配置,通过接口拿到数据和日历的日期进行匹配展示文字

vue获取某几天内的日期和星期几

javascript 复制代码
// 周末
getWeeks() {
  var day3 = new Date();
  let days = [];
  // 这里的6控制的是天数
  for (let i = 0; i <= 24 * 6; i += 24) {
    let dateItem = new Date(day3.getTime() + i * 60 * 60 * 1000);
    let y = dateItem.getFullYear();
    let m = dateItem.getMonth() + 1;
    let d = dateItem.getDate(); 
    m = this.addDate0(m);
    d = this.addDate0(d);
    let valueItem1 = y + "-" + m + "-" + d; 
    let valueItem = m + "/" + d; 
    var myddy = dateItem.getDay();
    var weekday = ["日", "一", "二", "三", "四", "五", "六"];
    days.push({
      day: `${valueItem1}`,
      date: `${valueItem}`,
      week: `${weekday[myddy]}`,
      name: `${i}`,
    });
  }
  this.winWeakList = days
  console.log(this.winWeakList);
},
addDate0(time) {
  if (time.toString().length == 1) {
    time = "0" + time.toString();
  }
  return time;
},

请假时长计算

javascript 复制代码
import moment from "moment";
//  我们的工作日是需要自己配置的
let workDayList = JSON.parse(window.localStorage.getItem("workDayList")) || []
let restDayList = JSON.parse(window.localStorage.getItem("restDayList")) || []

const WORK_START_TIME = 8.30; // 工作开始时间
const WORK_END_TIME = 17.30; // 工作下班时间
const BREAK_TIME = 1.30; // 休息时间
const BREAK_START = 12; // 上午休息时间
const BREAK_END = 13.30; // 下午休息结束时间
const WORK_TIME = 9; //
/**
 *
 * @param {*Number} num
 * @returns 分离出来的整数和小数
 */
// 获取某一天的下班时间
const startDateSupplement = (value) => {
 var year = value.getFullYear();
 var month = value.getMonth() + 1;
 var day = value.getDate();
 return new Date(`${year}-${month}-${day} 17:30:00`);
}
// 获取某一天的开始上班时间
const endDateSupplement = (value) => {
 var year = value.getFullYear();
 var month = value.getMonth() + 1;
 var day = value.getDate();
 console.log(year, month, day);
 return new Date(`${year}-${month}-${day} 08:30:00`);
}

// 使用二:跨日期计算
// sTime开始日期 eTime结束日期
const calcDay = (sTime, eTime) => {
  let days = leaveBydays(sTime, eTime, 1);
  return days;
};

const leaveBydays = (sTime, eTime, complement = 0) => {
  // 把传入的开始时间和结束时间的 分钟和秒钟格式化
  const stratTime =  moment(sTime).format('HH.mm');
  const endTime =  moment(eTime).format('HH.mm');

  let days
  const start1 = stratTime == "08.30" ? true : false
  const start2 = endTime == "17.30" ? true : false

  // 1. 开始时间等于上班时间和结束时间等于下班时间
  if (start1 && start2) {
    const to = moment(eTime).format('YYYY-MM-DD')
    const at = moment(sTime).format('YYYY-MM-DD')
    const originDay = moment(to).diff(at, 'day') + 1;

    let sday = sTime.getDate();

    let weekdays = 0;
    for (let i = 0; i < Math.round(originDay); i++) {
      let nowDay = new Date(new Date(sTime).setDate(sday + i));
      if (checkDay(nowDay)) {
        weekdays++;
      }
    }

    const finallyDays = originDay - weekdays
    const finallyIntHours = finallyDays * 9
    // console.log("开始时间等于上班时间和结束时间等于下班时间", finallyIntHours);
    return finallyIntHours;

  } else {

    // 1.计算出原始的天数
    const to = moment(eTime).format('YYYY-MM-DD HH:mm')
    const at = moment(sTime).format('YYYY-MM-DD HH:mm')
    let originDay = moment(to).diff(at, 'day') + 1;
    console.log(originDay);

    // 2.获取第一天的提起
    let sday = sTime.getDate();

    let weekdays = 0;
    for (let i = 0; i < Math.round(originDay); i++) {
      let nowDay = new Date(new Date(sTime).setDate(sday + i));
      if (checkDay(nowDay)) {
        weekdays++;
      }
    }
    //console.log(weekdays);

    let dayTime = 0;
    let dayOneTime;
    let dayLastTime;

    // 计算第一天的日期小时数
    const startToEndOne = startDateSupplement(sTime)
    const finallyResultOne = getTime(sTime, startToEndOne)
    //console.log("日期区间1", finallyResultOne);
    if (finallyResultOne != 0) {
      dayOneTime = `${finallyResultOne.hours}.${finallyResultOne.resultMinutes}`;
      dayTime += 1
    } else {
      dayOneTime = 0
    }

    const startToEndLast = endDateSupplement(eTime)
    const finallyResultLast = getTime(startToEndLast, eTime)
    //console.log("日期区间2", finallyResultLast);
    if (finallyResultLast != 0) {
      dayTime += 1
      dayLastTime = `${finallyResultLast.hours}.${finallyResultLast.resultMinutes}`;
    } else {
      dayLastTime = 0
    }

    console.log(`原始天数${originDay},周末天数${weekdays},相差${dayTime},第一天相差${dayOneTime},最后一天相差${dayLastTime}`);


    const finallyDays = originDay - weekdays - dayTime
    const finallyIntHours = finallyDays * 9
    // const finallyDayOneTime = dayOneTime?dayOneTime:0
    // const finallyDayLastTime = dayLastTime?dayLastTime:0

    const resultTime = Number(finallyIntHours) + parseFloat(dayOneTime) + parseFloat(dayLastTime)
    console.log(finallyDays, finallyIntHours, dayOneTime, dayLastTime, resultTime);
    return resultTime < 0 ? 0 : resultTime
  }
};


// 使用一:单个日期计算,当天
const getTime = (beginTime, endTime) => {
  if (checkDay(beginTime)) {
    return 0
  }
  var dateDiff = endTime.getTime() - beginTime.getTime();//时间差的毫秒数
  var dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000));//计算出相差天数

  var leave1 = dateDiff%(24*3600*1000)    //计算天数后剩余的毫秒数
  var hours = Math.floor(leave1/(3600*1000))//计算出小时数

  //计算相差分钟数
  var leave2 = leave1%(3600*1000)    //计算小时数后剩余的毫秒数
  var minutes = Math.floor(leave2/(60*1000))//计算相差分钟数

  //计算相差秒数
  var leave3 = leave2%(60*1000)      //计算分钟数后剩余的毫秒数
  var seconds = Math.round(leave3/1000)

  console.log(" 相差 "+dayDiff+"天 "+hours+"小时 "+minutes+" 分钟"+seconds+" 秒")
  // return dayDiff+"天 "+hours+"小时 "+minutes+" 分钟";
  let resultMinutes = 0
  if (minutes == 0) {
    resultMinutes = 0
  } else if (minutes < 30) {
    resultMinutes = 5
  } else if (minutes == 30){
    resultMinutes = 5
  } else if (minutes > 30) {
    hours = hours + 1
    // resultMinutes = minutes / 10
  }
  const finallyResult = {
    dayDiff: dayDiff,
    hours: hours,
    minutes: minutes,
    resultMinutes: resultMinutes,
    seconds: seconds
  }
  console.log(finallyResult);

  return finallyResult
}

//判断日期是否处于周六、周日(节假日后续完善)
const checkDay = (time) => {
  let flag = false;
  const formtTime =  moment(time).format('YYYY-MM-DD');
  if (!!workDayList.includes(formtTime)) {
    flag = false
    return flag
  }
  if (!!restDayList.includes(formtTime)) {
    flag = true
    return flag
  }
  let day = time.getDay();
  flag = day === 0 || day === 6 ? true : false;
  return flag;
};

export { calcDay, getTime};
javascript 复制代码
import { calcDay, getTime } from "@/utils/calcTime";
import moment from "moment";
// 日期计算
endTimeChange(val) {
  if (this.leaveDateRange.length>1) {
    this.form.startTime = this.leaveDateRange[0];
    this.form.endTime = this.leaveDateRange[1];
    this.addStartTime = this.DateFormat(this.form.startTime);
    this.addEndTime = this.DateFormat(this.form.endTime);
    const startDay = new Date(this.form.startTime).getDate();
    const endDay = new Date(this.form.endTime).getDate();
    const startTime = moment(this.form.startTime).format("HH:mm");
    const endTime = moment(this.form.endTime).format("HH:mm");
    if (startDay == endDay) {
      const timeRange = getTime(this.form.startTime, this.form.endTime);
      this.form.leaveLength = parseFloat(`${timeRange.hours}.${timeRange.resultMinutes}`) + "";
      console.log(this.form.leaveLength);
    } else {
      const day = calcDay(this.form.startTime, this.form.endTime);
      this.form.leaveLength = day;
    }
  }
},
DateFormat(value) {
  // 根据给定的字符串,得到特定的日期
  // var date = new Date(value);
  var year = value.getFullYear();
  var month = value.getMonth() + 1;
  var day = value.getDate();
  var hour = value.getHours();
  var min = value.getMinutes();
  var sec = value.getSeconds();
  const dateStr = `${String(year)}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")} ${String(hour).padStart(2, "0")}:${String(
    min
  ).padStart(2, "0")}:${String(sec).padStart(2, "0")}`;
  return dateStr;
},
相关推荐
m0_748236584 分钟前
本地部署轻量级web开发框架Flask并实现无公网ip远程访问开发界面
前端·tcp/ip·flask
Jet_closer_burning14 分钟前
Vue2 和 Vue3 的响应式原理对比
前端·javascript·vue.js·html
xing251642 分钟前
pytest-html
前端·html·pytest
努力的白熊嗨1 小时前
一文带你搞懂前端大文件上传
前端·javascript
茂茂在长安1 小时前
Linux 命令大全完整版(11)
java·linux·运维·服务器·前端·centos
Violet5151 小时前
ECMAScript规范解读——this的判定
javascript
知识分享小能手1 小时前
Html5学习教程,从入门到精通,HTML5 简介语法知识点及案例代码(1)
开发语言·前端·javascript·学习·前端框架·html·html5
IT、木易1 小时前
大白话React第二章深入理解阶段
前端·javascript·react.js
晚安7202 小时前
Ajax相关
前端·javascript·ajax
图书馆钉子户2 小时前
怎么使用ajax实现局部刷新
前端·ajax·okhttp