vue项目开发笔记记录(一)

简介: vue项目开发笔记记录

api接口封装


1.接口函数封装

import request from '@/utils/request'
import apiUrl from '../apiUrl'

// 根据主键获取单条记录
export function itemById(params) {
  return request({
    url: apiUrl.dataSourceApi.getItemById,
    method: 'get',
    params: params
  })
}

2.接口地址封装

export default {
  // 数据来源管理
  dataSourceApi: {
    queryAllData: '/web/bdp/datasourcemanager/datasourceinfo/all/1', // 获取所有来源数据源信息
    getItemById: '/web/bdp/datasourcemanager/datasourceinfo/item', // 根据主键获取单条记录
    getAllData: '/web/bdp/datasourcemanager/databaserelease/all/1', // 获取数据来源已支持的数据库类型
  },
}

vue常用组件


折线图组件

<template>
  <div class="trend-map">
    <div id="tendChart" />
  </div>
</template>

<script>
import echarts from 'echarts'
export default {
  name: 'TrendMap',
  props: {
    objData: {
      type: Object,
      default: function() {
        return {}
      }
    }
  },
  data() {
    return {
      yData: [820, 932, 901, 934, 1290, 1330, 1320],
      xData: [
        '2020-05-11',
        '2020-05-12',
        '2020-05-13',
        '2020-05-14',
        '2020-05-15',
        '2020-05-16',
        '2020-05-17']
    }
  },
  watch: {
    objData: {
      handler(val) {
        // this.queryNetworkBandwith()
      },
      deep: true
    }
  },
  mounted() {
    this.draw() // 临时展示作用
  },
  methods: {
    queryTPSTransation() {
      const params = {
        number: '40',
        period: this.objData.period,
        rtTaskNo: this.objData.rtTaskNo
      }
      queryTPSTransation(params).then(res => {
        if (res.code === 0) {
          this.xData = res.data.time
          this.yData = res.data.data
          this.draw()
        }
      })
    },
    draw() {
      var option = {
        grid: {
          top: '20%',
          left: '5%',
          right: '5%',
          bottom: '15%'
        },
        title: {
          text: '存储趋势图',
          textStyle: {
            color: '#fff',
            fontSize: 16
          },
          left: '1%',
          top: '3%',
          bottom: '20%'
        },
        color: ['#00a3e5'],
        tooltip: {
          trigger: 'axis',
          padding: [2, 10],
          textStyle: {
            fontSize: 16
          },
          formatter: function(params) {
            var result = params[0].axisValue + '<br/>'
            params.forEach(function(item) {
              result += item.seriesName + ':' + item.value + ' MB</br>'
            })
            return result
          }
        },
        xAxis: [{
          type: 'category',
          axisLine: {
            show: true,
            lineStyle: {
              color: '#fff'
            }
          },
          splitLine: {
            show: false
          },
          boundaryGap: true,
          data: this.xData

        }],
        yAxis: [{
          name: 'MB',
          type: 'value',
          splitLine: {
            show: false
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            show: true,
            margin: 20,
            textStyle: {
              color: '#fff'
            }
          },
          axisTick: {
            show: true
          }
        }],
        series: [{
          name: '存储趋势图',
          type: 'line',
          smooth: true, // 是否平滑
          showAllSymbol: true,
          symbol: 'none',
          symbolSize: 5,
          lineStyle: {
            normal: {
              color: '#00a3e5',
              width: 2
            }
          },
          data: this.yData
        }]
      }
      // 初始化图表
      const chartObj = echarts.init(document.getElementById('tendChart'))
      chartObj.setOption(option)
      if (option && typeof option === 'object') {
        chartObj.setOption(option)
      }
    }
  }
}
</script>

<style scoped lang="scss">
.trend-map{
  margin-top: 15px;
  background-color: #343d47;
}
#tendChart {
  height: 400px;
}
</style>

柱状图组件

<template>
  <div class="trend-map">
    <div class="occupy-more" @click="navToMoreDetail">更多<i class="fa fa-angle-right fa-fw" /></div>
    <div id="occupyChart" />
  </div>
</template>

<script>
import echarts from 'echarts'
export default {
  name: 'TrendMap',
  props: {
    objData: {
      type: Object,
      default: function() {
        return {}
      }
    }
  },
  data() {
    return {
      yData: Array.from({ length: 10 }, v => Math.random() * 10240000),
      xData: Array.from({ length: 10 }, (v, w) => 'powersi' + w)
    }
  },
  computed: {},
  watch: {
    objData: {
      handler(val) {
        // this.queryNetworkBandwith()
      },
      deep: true
    }
  },
  mounted() {
    this.draw() // 临时展示作用
  },
  methods: {
    queryTPSTransation() {
      const params = {
        number: '40',
        period: this.objData.period,
        rtTaskNo: this.objData.rtTaskNo
      }
      queryTPSTransation(params).then(res => {
        if (res.code === 0) {
          this.xData = res.data.time
          this.yData = res.data.data
          this.draw()
        }
      })
    },
    draw() {
      var option = {
        grid: {
          top: '20%',
          left: '2%',
          right: '5%',
          bottom: '15%',
          containLabel: true
        },
        title: {
          text: '表占用存储Top',
          textStyle: {
            color: '#fff',
            fontSize: 16
          },
          left: '1%',
          top: '3%',
          bottom: '20%'
        },
        tooltip: {
          trigger: 'axis',
          padding: [2, 10],
          textStyle: {
            fontSize: 16
          },
          formatter: function(data) {
            // 格式化为字节并格式化tooltip
            var filesize = data[0].value
            var result = data[0].axisValue + '<br/>'
            if (filesize == null || filesize == '') {
              return '0 Bytes'
            }
            var unitArr = [
              'Bytes',
              'KB',
              'MB',
              'GB',
              'TB',
              'PB',
              'EB',
              'ZB',
              'YB'
            ]
            var index = 0
            var srcsize = parseFloat(filesize)
            index = Math.floor(Math.log(srcsize) / Math.log(1024))
            var size = srcsize / Math.pow(1024, index)
            size = size.toFixed(2) // 保留的小数位数
            result +=
              data[0].seriesName + ':' + size + unitArr[index] + '</br>'
            return result
          }
        },
        color: ['#00a3e5'],
        xAxis: {
          data: this.xData,
          type: 'category',
          boundaryGap: [0, 0.01],
          show: true,
          axisLine: {
            show: true,
            lineStyle: {
              color: '#fff'
            }
          }
        },

        yAxis: {
          type: 'value',
          data: this.yData,
          axisTick: {
            show: true
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#fff'
            }
          },
          axisLabel: {
            interval: 0,
            margin: 15
          }
        },
        series: [
          {
            name: '2011年',
            type: 'bar',
            data: this.yData,
            barWidth: 20, // 柱图宽度
            itemStyle: {
              normal: {
                borderRadius: 10,
                label: {
                  show: true, // 开启显示
                  position: 'top', // 在上方显示
                  textStyle: {
                    // 数值样式
                    color: '#fff',
                    fontSize: 16,
                    top: 10
                  },
                  formatter: function(data) {
                    // 格式化为字节
                    var filesize = data.value
                    if (filesize == null || filesize == '') {
                      return '0 Bytes'
                    }
                    var unitArr = [
                      'Bytes',
                      'KB',
                      'MB',
                      'GB',
                      'TB',
                      'PB',
                      'EB',
                      'ZB',
                      'YB'
                    ]
                    var index = 0
                    var srcsize = parseFloat(filesize)
                    index = Math.floor(Math.log(srcsize) / Math.log(1024))
                    var size = srcsize / Math.pow(1024, index)
                    size = size.toFixed(2) // 保留的小数位数
                    return size + unitArr[index]
                  }
                }
              }
            }
          }
        ]
      }
      // 初始化图表
      const chartObj = echarts.init(document.getElementById('occupyChart'))
      chartObj.setOption(option)
      if (option && typeof option === 'object') {
        chartObj.setOption(option)
      }
    },
    navToMoreDetail() {
      this.$router.push('/dataMap/myData')
    }
  }
}
</script>

<style scoped lang="scss" scoped>
.trend-map {
  margin-top: 15px;
  background-color: #343d47;
  position: relative;
}

.occupy-more {
  position: absolute;
  right: 40px;
  top: 10px;
  z-index: 999;
  font-size: 14px;
  cursor: pointer;
  padding: 3px 3px 3px 6px;
  &:hover{
    background-color: #212a33;
    border-radius: 3px;
  }
}
#occupyChart {
  height: 400px;
}
</style>

echart tootip格式化

tooltip: {
  trigger: 'axis',
  padding: [2, 10],
  textStyle: {
    fontSize: 16
  },
  formatter: function (data) { // 格式化为字节并格式化tooltip
    var filesize = data[0].value
    var result = data[0].axisValue + '<br/>'
    if (filesize == null || filesize == '') {
      return '0 Bytes'
    }
    var unitArr = new Array('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB')
    var index = 0
    var srcsize = parseFloat(filesize)
    index = Math.floor(Math.log(srcsize) / Math.log(1024))
    var size = srcsize / Math.pow(1024, index)
    size = size.toFixed(2) // 保留的小数位数
    result += data[0].seriesName + ':' + size + unitArr[index] + '</br>'
    return result
  }
},

随机生成数据

yData: Array.from({ length: 10 }, v => Math.random() * 10240000),
xData: Array.from({ length: 10 }, (v, w) => 'powersi' + w)

标准头部

 <header>
      <span class="title">服务器管理</span>
      <div class="query">
        <el-form :inline="true" class="demo-form-inline">
          <el-form-item>
            <el-input v-model="dbName" clearable placeholder="请输入服务器名称" @keyup.enter.native="getData">
              <template slot="prepend">搜索</template>
              <el-button slot="append" icon="el-icon-search" @click.native.prevent="getData" />
            </el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="el-icon-plus" @click="showDatabase = true">新增服务器</el-button>
          </el-form-item>
        </el-form>
      </div>
    </header>

element-ui表格

<div class=" taskOperationMonitoring">
      <!-- 服务器管理 -->
      <div class="data-sourse">
        <el-table :data="tableData" height="650" stripe style="width: 100%;">
          <el-table-column type="index" label="序号" align="center" width="50" />
          <el-table-column prop="ips" label="服务器IP地址" align="center" width="180" />
          <el-table-column prop="port" label="端口" align="center" />
          <el-table-column prop="host" label="主机" align="center" width="180" />
          <el-table-column prop="username" label="用户名" align="center" />
          <el-table-column prop="password" label="密码" align="center" />
          <el-table-column prop="privat" label="私钥" align="center" />
          <el-table-column prop="cpu" label="CPU核数" align="center" />
          <el-table-column prop="storage" label="内存(GB)" align="center" />
          <el-table-column prop="sd" label="磁盘大小(GB)" align="center" />
          <el-table-column prop="isSD" label="是否SSD" align="center">
            <template slot-scope="scope">
              <span v-if="scope.taskStas= '1'" class="success">正常</span>
              <span v-else class="danger">异常</span>
            </template>
          </el-table-column>
          <el-table-column prop="other" label="备注" align="center" />
          <el-table-column label="操作" align="center" width="140">
            <template slot-scope="scope">
              <el-button type="primary" size="mini" @click="details(scope.row)">编辑</el-button>
              <el-button type="primary" size="mini" @click="deleteItem(scope.row)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination
          :current-page="currentPage"
          :page-sizes="[10, 20, 30, 40]"
          :page-size="pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
</div>

data() {
    return {
      tableData: Array(15).fill(item),
      currentPage: 1,
      pageSize: 20,
      total: 20
    }
}

页面跳转清除定时器

data() {            
    return {                              
        timer: null  // 定时器名称          
    }        
},
mounted(){
this.timer = (() => {
    // 某些操作
}, 1000)
},
 
//最后在beforeDestroy()生命周期内清除定时器:
 
beforeDestroy() {
    clearInterval(this.timer);        
    this.timer = null;
}

vue通用模板

<template>
  <div class="">
    地区间参保覆盖情况分析
  </div>
</template>

<script>
export default {
  name: '',
  components: {},
  mixins: [],
  props: {},
  data() {
    return {}
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {},
  methods: {},
}
</script>

<style scoped lang="scss">
</style>

filters过滤器


引入

import { toThousandFilter, numberToPercent } from '../../../filters'
// import parseTime, formatTime and set to filter
export { parseTime, formatTime } from '@/utils'

/**
 * Show plural label if time is plural number
 * @param {number} time
 * @param {string} label
 * @return {string}
 */
function pluralize(time, label) {
  if (time === 1) {
    return time + label
  }
  return time + label + 's'
}

/**
 * @param {number} time
 */
export function timeAgo(time) {
  const between = Date.now() / 1000 - Number(time)
  if (between < 3600) {
    return pluralize(~~(between / 60), ' minute')
  } else if (between < 86400) {
    return pluralize(~~(between / 3600), ' hour')
  } else {
    return pluralize(~~(between / 86400), ' day')
  }
}

/**
 * Number formatting
 * like 10000 => 10k
 * @param {number} num
 * @param {number} digits
 */
export function numberFormatter(num, digits) {
  const si = [
    { value: 1E18, symbol: 'E' },
    { value: 1E15, symbol: 'P' },
    { value: 1E12, symbol: 'T' },
    { value: 1E9, symbol: 'G' },
    { value: 1E6, symbol: 'M' },
    { value: 1E3, symbol: 'k' }
  ]
  for (let i = 0; i < si.length; i++) {
    if (num >= si[i].value) {
      return (num / si[i].value).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
    }
  }
  return num.toString()
}

/**
 * 10000 => "10,000"
 * @param {number} num
 */
export function toThousandFilter(num) {
  return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}

/**
 * Upper case first char
 * @param {String} string
 */
export function uppercaseFirst(string) {
  return string.charAt(0).toUpperCase() + string.slice(1)
}

/**
 * money formatting
 * like 10000 => 1万元
 * @param {number | String} value
 */

export function moneyFilter(value) {
  if (!value) return '0元'
  let result = 0
  if (parseFloat(value) >= 10000) {
    result = (value / 10000).toFixed(2) + '万元'
  } else if (parseFloat(value) >= 100000000) {
    result = (value / 100000000).toFixed(2) + '亿元'
  } else {
    result = value + '元'
  }
  return result
}

/**
 * count formatting
 * like 10000 => 1万次
 * @param {number | String} value
 */

export function conutFilter(value) {
  if (!value) return '0次'
  let result = 0
  if (parseFloat(value) >= 10000) {
    result = (value / 10000).toFixed(2) + '万次'
  } else if (parseFloat(value) >= 100000000) {
    result = (value / 100000000).toFixed(2) + '亿次'
  } else {
    result = value + '次'
  }
  return result
}

export function numberToPercent(value, total, fixed) {
  // console.log(value)
  // console.log(total)
  // console.log((value / total * 100).toFixed(fixed) + '%')
  return (value / total * 100).toFixed(fixed) + '%'
}

基本路由配置

{
    path: '/assistDecision',
    component: Layout,
    alwaysShow: true,
    redirect: '/assistDecision/medicalPriceAnalyze',
    meta: {
      title: '数据分析平台',
      icon: 'icon'
    },
    children: [
      {
        path: 'medicalPriceAnalyze',
        component: () => import('@/views/assist-decision/medical-price-analyze/index'),
        name: 'medicalPriceAnalyze',
        meta: { title: '医疗机构费用分析', icon: 'icon', noCache: true }
      }
}

utils公共函数使用


引入

import { deepClone } from '@/utils/index'

获取select的label值

/**
 * 获取select的label值
 * @param value 选中id
 * @param arr   原数组
 * @param idName  id的字段名
 * @param labelName  name的字段名
 * @returns {*}
 */
export function getSelectLabel(value, arr, idName, labelName) {
  return arr.find(item => {
    return item[idName] === value
  })[labelName]
}

时间格式化

/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string | null}
 */
export function parseTime(time, cFormat) {
  if (arguments.length === 0) {
    return null
  }
  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if ((typeof time === 'string')) {
      if ((/^[0-9]+$/.test(time))) {
        // support "1548221490638"
        time = parseInt(time)
      } else {
        // support safari
        // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
        time = time.replace(new RegExp(/-/gm), '/')
      }
    }

    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
    const value = formatObj[key]
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') {
      return ['日', '一', '二', '三', '四', '五', '六'][value]
    }
    return value.toString().padStart(2, '0')
  })
  return time_str
}

时间转几小时前

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (('' + time).length === 10) {
    time = parseInt(time) * 1000
  } else {
    time = +time
  }
  const d = new Date(time)
  const now = Date.now()

  const diff = (now - d) / 1000

  if (diff < 30) {
    return '刚刚'
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + '分钟前'
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + '小时前'
  } else if (diff < 3600 * 24 * 2) {
    return '1天前'
  }
  if (option) {
    return parseTime(time, option)
  } else {
    return (
      d.getMonth() +
      1 +
      '月' +
      d.getDate() +
      '日' +
      d.getHours() +
      '时' +
      d.getMinutes() +
      '分'
    )
  }
}

获取url的参数

/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url) {
  url = url == null ? window.location.href : url
  const search = url.substring(url.lastIndexOf('?') + 1)
  const obj = {}
  const reg = /([^?&=]+)=([^?&=]*)/g
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1)
    let val = decodeURIComponent($2)
    val = String(val)
    obj[name] = val
    return rs
  })
  return obj
}

获取字节长度

/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
  // returns the byte length of an utf8 string
  let s = str.length
  for (var i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i)
    if (code > 0x7f && code <= 0x7ff) {
      s++
    } else if (code > 0x7ff && code <= 0xffff) s += 2
    if (code >= 0xDC00 && code <= 0xDFFF) i--
  }
  return s
}

清除数组

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
  const newArray = []
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i])
    }
  }
  return newArray
}

json转数组

/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json) {
  if (!json) return ''
  return cleanArray(
    Object.keys(json).map(key => {
      if (json[key] === undefined) return ''
      return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
    })
  ).join('&')
}

字符串转对象

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = url.split('?')[1]
  if (!search) {
    return {}
  }
  return JSON.parse(
    '{"' +
    decodeURIComponent(search)
      .replace(/"/g, '\\"')
      .replace(/&/g, '","')
      .replace(/=/g, '":"')
      .replace(/\+/g, ' ') +
    '"}'
  )
}

富文本过滤成普通文本

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement('div')
  div.innerHTML = val
  return div.textContent || div.innerText
}

对象克隆

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target, source) {
  if (typeof target !== 'object') {
    target = {}
  }
  if (Array.isArray(source)) {
    return source.slice()
  }
  Object.keys(source).forEach(property => {
    const sourceProperty = source[property]
    if (typeof sourceProperty === 'object') {
      target[property] = objectMerge(target[property], sourceProperty)
    } else {
      target[property] = sourceProperty
    }
  })
  return target
}

toggle效果

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return
  }
  let classString = element.className
  const nameIndex = classString.indexOf(className)
  if (nameIndex === -1) {
    classString += '' + className
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length)
  }
  element.className = classString
}

获取当前时间

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type) {
  if (type === 'start') {
    return new Date().getTime() - 3600 * 1000 * 24 * 90
  } else {
    return new Date(new Date().toDateString())
  }
}

防抖函数

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result

  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}

vue项目开发笔记记录(二):https://developer.aliyun.com/article/1483518

相关文章
|
1天前
|
资源调度 JavaScript 前端开发
【vue】vue中的路由vue-router,vue-cli脚手架详细使用教程
【vue】vue中的路由vue-router,vue-cli脚手架详细使用教程
|
1天前
|
JavaScript 前端开发
vue组件化开发流程梳理,拿来即用
vue组件化开发流程梳理,拿来即用
|
1天前
|
JavaScript Go
Vue路由跳转及路由传参
Vue路由跳转及路由传参
|
2天前
|
JavaScript 前端开发 BI
采用前后端分离Vue,Ant-Design技术开发的(手麻系统成品源码)适用于三甲医院
开发环境 技术架构:前后端分离 开发语言:C#.net6.0 开发工具:vs2022,vscode 前端框架:Vue,Ant-Design 后端框架:百小僧开源框架 数 据 库:sqlserver2019
采用前后端分离Vue,Ant-Design技术开发的(手麻系统成品源码)适用于三甲医院
|
4天前
|
监控 JavaScript
Vue中的数据变化监控与响应——深入理解Watchers
Vue中的数据变化监控与响应——深入理解Watchers
|
5天前
|
JavaScript
【vue】如何跳转路由到指定页面位置
【vue】如何跳转路由到指定页面位置
8 0
|
5天前
|
JSON JavaScript 前端开发
【vue】假数据的选择和使用
【vue】假数据的选择和使用
11 1
|
5天前
|
JavaScript 前端开发
【vue】iview如何把input输入框和点击输入框之后的边框去掉
【vue】iview如何把input输入框和点击输入框之后的边框去掉
12 0
|
5天前
|
JavaScript 安全 前端开发
Vue 项目中的权限管理:让页面也学会说“你无权访问!
Vue 项目中的权限管理:让页面也学会说“你无权访问!
14 3
|
5天前
|
JavaScript 前端开发 开发者
Vue的神奇解锁:冒险的开始
Vue的神奇解锁:冒险的开始
5 1