vue3.0 搭建项目总结(详细步骤)


Posted in Javascript onMay 20, 2019

1.环境配置

项目中的不同开发环境有很多依赖配置,所以可以根据环境设置不同的配置,以免在不同环境经常修改文件

1 在根目录下创建 `.env.[环境]` 文件,可以在不同环境设置一些配置变量,如图

vue3.0 搭建项目总结(详细步骤)

vue3.0 搭建项目总结(详细步骤) 

.env.dev 文件

2.eslint 配置

在package.json 文件里面有一个eslintConfig对象,可设置rules: 如图

vue3.0 搭建项目总结(详细步骤)

3.配置svg

在vue.config.js 里面需在module.exports对象里面设置

chainWebpack: config => {
  config.module.rules.delete('svg') // 重点:删除默认配置中处理svg,//const svgRule = config.module.rule('svg') //svgRule.uses.clear()
  config.module
   .rule('svg-sprite-loader')
   .test(/\.svg$/)
   .use('svg-sprite-loader')
   .loader('svg-sprite-loader')
   .options({
    symbolId: 'icon-[name]'
   })
 }

svg component

<template>
 <svg :class="svgClass" aria-hidden="true">
  <use :xlink:href="iconName" rel="external nofollow" />
 </svg>
</template>

<script>
export default {
 name: 'SvgIcon',
 props: {
  iconClass: {
   type: String,
   required: true
  },
  className: {
   type: String,
   default: ''
  }
 },
 computed: {
  iconName() {
   return `#icon-${this.iconClass}`
  },
  svgClass() {
   if (this.className) {
    return 'svg-icon ' + this.className
   } else {
    return 'svg-icon'
   }
  }
 }
}
</script>

<style scoped>
.svg-icon {
 width: 1em;
 height: 1em;
 vertical-align: -0.15em;
 fill: currentColor;
 overflow: hidden;
}
</style>

```

使用svg组件

import SvgIcon from '@/components/SvgIcon.vue'
// 设置全局组件svgIcon
Vue.component('svg-icon', SvgIcon)
const req = require.context('./assets/svg', true, /\.svg$/) // 查询文件加下面的svg文件
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req) // 全局导入svg文件

2.通用组件

级联(多选且可以选择全部)组件

安装插件 multi-cascader-base-ele

使用

import multiCascader from 'multi-cascader-base-ele'
Vue.use(multiCascader)

-- 支持选择全部

<template>
 <div>
  <MultiTestCascader v-model="selectedOptions" class="multi-cascader" :props="customProps" :options="options" multiple filterable select-children :show-all-levels="false" clearable only-out-put-leaf-node @change="cascaderChange" />
 </div>
</template>
<script>
export default {
 props: {
 // 传入级联列表数据
  options: {
   type: Array,
   default: () => []
  },
  // 传入选择数据
  list: {
   type: Array,
   default: () => []
  },
  // 自定义相关字段
  customProps: {
   type: Object,
   default: () => {
    return {
     label: 'label',
     value: 'value',
     children: 'children'
    }
   }
  },
  // 显示全部类型 1 全部二级/全部三级 2 全部二级分类/全部三级分类 3 全省/全市
  type: {
   type: String,
   default: () => '1'
  }
 },
 data() {
  return {
   selectedOptions: this.list,
   listStatus: true
  }
 },
 created() {

 },
 watch: {
  options(newValue, oldValue) {
   this.setListDisabled(newValue)
   this.addAllLabel(newValue)
  },
  list(newValue) {
   if (this.listStatus) {
    this.cascaderChange(newValue)
    this.listStatus = false
   }
  }
 },
 mounted() {
  this.setListDisabled(this.options)
  this.addAllLabel(this.options)
 },
 methods: {
  addAllLabel(list) {
   list.forEach(val => {
    if (val[this.customProps.children] && val[this.customProps.children].length > 0 && val[this.customProps.children][0][this.customProps.label] !== (this.type === '1' ? '全部一级' : (this.type === '2' ? '全部一级分类' : (this.type === '3' ? '全省' : '')))) {
     if (val[this.customProps.children].length > 1) {
      val[this.customProps.children].unshift({
       [this.customProps.label]: this.type === '1' ? '全部二级' : (this.type === '2' ? '全部二级分类' : (this.type === '3' ? '全省' : '')),
       [this.customProps.value]: val[this.customProps.value],
       [this.customProps.children]: null
      })
     }
     val[this.customProps.children].forEach(v => {
      if (v[this.customProps.children] && v[this.customProps.children].length > 1 && v[this.customProps.children][0][this.customProps.label] !== (this.type === '1' ? '全部二级' : (this.type === '2' ? '全部二级分类' : (this.type === '3' ? '全省' : '')))) {
       if (v[this.customProps.children].length > 1) {
        v[this.customProps.children].unshift({
         [this.customProps.label]: this.type === '1' ? '全部三级' : (this.type === '2' ? '全部三级分类' : (this.type === '3' ? '全市' : '')),
         [this.customProps.value]: v[this.customProps.value],
         [this.customProps.children]: null
        })
       }
      }
     })
    }
   })
  },
  setListDisabled(list) {
   const label = this.customProps.label
   const value = this.customProps.value
   const children = this.customProps.children
   list.forEach(val => {
    val.disabled = false
    if (val[children]) this.setListDisabled(val[children])
   })
  },
  cascaderChange(itemList) {
   if (!itemList || itemList.length === 0) {
    this.selectedOptions = []
   }
   this.setListDisabled(this.options)
   const label = this.customProps.label
   const value = this.customProps.value
   const children = this.customProps.children
   this.options.forEach((v, l) => {
    this.selectedOptions.forEach(val => {
     if (val[0] === '-1') {
      if (v[value] !== '-1') v.disabled = true
      else v.disabled = false
      if (v[children] && v[children].length > 0) {
       v[children].forEach(c => { c.disabled = true })
      }
     } else {
      if (v[value] === '-1') v.disabled = true
      else v.disabled = false
      if (v[children] && v[children].length > 0) {
       v[children].forEach(c => { c.disabled = false })
      }
     }
     if (val.length === 2 && v[value] === val[0] && v[children]) {
      v[children].forEach((item, num) => {
       item.disabled = false
       if (val[0] === val[1] && item[value] === val[1]) {
        item.disabled = false
       } else {
        if (val[0] === val[1] && num !== 0) {
         item.disabled = true
         if (item[children]) {
          item[children].forEach(i => {
           i.disabled = true
          })
         }
        }
        if (val[0] !== val[1] && num === 0 && v[children].length > 1) item.disabled = true
       }
       // this.options[l][children][0].disabled = true
      })
     }
     if (val.length === 3 && v[value] === val[0] && v[children]) {
      v[children].forEach((item, j) => {
       // let status = false
       if (item[children] && val[1] === item[value]) {
        item.disabled = false
        item[children].forEach((i, index) => {
         i.disabled = false
         if (i[value] === val[2]) status = true
         if (i[value] === val[2] && val[1] === val[2]) {
          i.disabled = false
         } else {
          if (val[1] !== val[2] && index === 0 && v[children].length > 1) i.disabled = true
          if (val[1] === val[2] && index !== 0) i.disabled = true
         }
        })
        // this.options[0].disabled = true
        this.options[l][children][0].disabled = true
        // return status
       }
      })
     }
    })
   })
   this.selectedOptions = this.selectedOptions.map(val => {
    if (val.length === 2 && val[0] === val[1]) return [val[0]]
    if (val.length === 1 && val[0] === '-1') return [val[0]]
    if (val.length === 3 && val[1] === val[2]) return [val[0], val[1]]
    return val
   })
   const item = this.selectedOptions[this.selectedOptions.length - 1]
   const length = this.selectedOptions.length
   let status = -1
   this.selectedOptions.some((val, index) => {
    if ((length - 1) === index) return true
    if (item.length === val.length) {
     if (item.join(',') === val.join(',')) {
      status = 1
      return true
     }
    }
    if (item.length > val.length) {
     if (item.join(',').includes(val.join(','))) {
      status = 2
      return true
     }
    }
    if (val.length > item.length) {
     if (val.join(',').includes(item.join(','))) {
      status = 3
      return true
     }
    }
   })
   if (status !== -1) {
    this.selectedOptions.splice(this.selectedOptions.length - 1, 1)
   }
   this.$emit('update:list', this.selectedOptions)
  }
 }
}
</script>

上传(支持图片/视频/裁剪图片/拖拽)

安装插件

vuedraggable axios vue-cropper

代码

<!-- -->
<template>
 <div class="image-draggable">
  <draggable v-model="draggableList" @end="onEnd">
   <!-- <transition-group> -->
   <div v-for="(item, index) in draggableList" :key="index" class="image-list">
    <template v-if="item.isImg">
     <img :src="item.displayUrl" alt="" srcset="" style="width: 148px; height: 148px;">
     <div class="icon">
      <span @click="viewImage(item.displayUrl)">
       <svg-icon icon-class="view" class="icon-size" style="margin-right: 10px;"></svg-icon>
      </span>
      <span @click="remove(index)">
       <svg-icon icon-class="delete" class="icon-size"></svg-icon>
      </span>
     </div>
    </template>
    <template v-if="!item.isImg">
     <video :src="item.displayUrl" :ref="item.id" :id="item.id" :poster="item.coverUrl" style="width: 148px; height: 148px;">
     </video>
     <div class="icon">
      <span v-if="item.isPlay" @click="play(item)" class="video-icon">
       <svg-icon icon-class="play" class="icon-size"></svg-icon>
      </span>
      <span v-if="!item.isPlay" @click="pause(item)" class="video-icon">
       <svg-icon icon-class="pause" class="icon-size"></svg-icon>
      </span>
      <span @click="fullPlay(item)" class="video-icon">
       <svg-icon icon-class="full" class="icon-size"></svg-icon>
      </span>
      <span @click="remove(index)">
       <svg-icon icon-class="delete" class="icon-size"></svg-icon>
      </span>
     </div>
    </template>
   </div>

   <!-- </transition-group> -->
  </draggable>
  <el-upload :id="uploadId" :disabled="isDiabled" :action="uploadUrl" class="image-upload" :headers="headers" :accept="accept" list-type="picture-card" :show-file-list="false" :on-preview="handlePictureCardPreview" :on-progress="handleProgress" :on-change="fileChange" :auto-upload="!isCropper" :on-remove="handleRemove" :on-success="imageSuccess" :before-upload="fileBeforeUpload">
   <i class="el-icon-plus"></i>
   <el-progress :percentage="percentage" v-if="isUpload && isLoading" :show-text="false"></el-progress>
  </el-upload>
  <el-dialog :visible.sync="dialogVisible">
   <img width="100%" :src="dialogImageUrl" alt="">
  </el-dialog>
  <el-dialog :visible.sync="modifyCropper">
   <div :style="{height: (autoCropHeight + 100) + 'px'}">
    <vueCropper ref="cropper" :img="imgSrc" :outputSize="option.size" :outputType="option.outputType" :info="true" :full="option.full" :canMove="option.canMove" :canMoveBox="option.canMoveBox" :original="option.original" :autoCrop="option.autoCrop" :autoCropHeight="autoCropHeight" :autoCropWidth="autoCropWidth" :fixedBox="option.fixedBox" @realTime="realTime" @imgLoad="imgLoad"></vueCropper>
   </div>
   <span slot="footer" class="dialog-footer">
    <el-button @click="modifyCropper = false">取 消</el-button>
    <el-button type="primary" @click="uploadCropperImage">确 定</el-button>
   </span>
  </el-dialog>
 </div>
</template>

<script>
// 拖拽
import draggable from 'vuedraggable'
// 裁剪
import { VueCropper } from 'vue-cropper'
// 上传地址
import { upload } from '@/api'
import { getToken } from '@/util/auth'
import axios from 'axios'

export default {
 name: '',
 data() {
  return {
   headers: {
    Authorization: getToken()
   },
   uploadUrl: upload,
   displayUrl: '',
   dialogImageUrl: '',
   dialogVisible: false,
   percentage: 0,
   accept: '',
   draggableList: [],
   isUpload: false,
   modifyCropper: false,
   isDiabled: false,
   cropperImage: {
   },
   uploadId: 'id' + Date.now(),
   imgSrc: '',
   option: {
    size: 0.5,
    full: true, // 输出原图比例截图 props名full
    outputType: 'png',
    canMove: true,
    original: true,
    canMoveBox: false,
    autoCrop: true,
    fixedBox: true
   }
  }
 },
 props: {
  // 已存在的文件
  fileList: {
   type: Array,
   default() {
    return [
    ]
   }
  },
  // 返回类型 Array 数组 Object 对象
  returnType: {
   type: String,
   default: 'Array'
  },
  // 自定义对象
  customObject: {
   type: Object,
   default: () => { }
  },
  // 上传的最大个数
  maxNum: {
   type: Number,
   required: true,
   default: 1
  },
  // 单位MB
  maxSize: {
   type: Number,
   default: 15
  },
  autoCropWidth: {
   type: Number,
   default: 180
  },
  autoCropHeight: {
   type: Number,
   default: 180
  },
  // 上传类型 All 图片/视频 image 图片 video视频
  acceptType: {
   type: String,
   default: 'All'
  },
  // 是否裁剪
  isCropper: {
   type: Boolean,
   default: false
  },
  // 是否显示加载条
  isLoading: {
   type: Boolean,
   default: true
  },

  outputSize: {
   type: Number,
   default: 1
  },
  outputType: {
   type: String,
   default: 'jpeg'
  }
 },
 components: {
  draggable,
  VueCropper
 },
 watch: {
  draggableList(newValue, oldValue) {
   this.getElement(this.draggableList.length)
  },
  fileList(newValue, oldValue) {
   this.draggableList = newValue
   this.initImage()
  }
 },

 computed: {},

 mounted() {
  if (this.acceptType === 'All') {
   this.accept = 'image/png, image/jpeg, image/gif, image/jpg, .mp4,.qlv,.qsv,.ogg,.flv,.avi,.wmv,.rmvb'
  }
  if (this.acceptType === 'image') {
   this.accept = 'image/png, image/jpeg, image/gif, image/jpg'
  }
  if (this.acceptType === 'video') {
   this.accept = '.mp4,.qlv,.qsv,.ogg,.flv,.avi,.wmv,.rmvb'
  }
  this.initImage()
 },
 methods: {
  // 获取五位数的随机数
  getRandom() {
   return (((Math.random() + Math.random()) * 10000) + '').substr(0, 5).replace('.', 0)
  },
  initImage() {
   const _this = this
   // console.log('file', this.fileList)
   if (this.fileList.length > 0) {
    this.draggableList = this.fileList.map(val => {
     let displayUrl = ''
     let coverUrl = ''
     let isImg = true
     const files = (val.url ? val.url : val).split(',')
     if (files.length === 3) {
      displayUrl = files[1]
      coverUrl = files[2]
      isImg = false
     } else if (files.length === 1) {
      displayUrl = (val.url ? val.url : val)
      isImg = true
     }
     const fileObj = Object.assign({}, {
      coverUrl: coverUrl,
      displayUrl: displayUrl,
      isImg: isImg,
      isPlay: true,
      name: Date.now(),
      url: (val.url ? val.url : val),
      id: val.id || Date.now() + _this.getRandom()
     })
     return fileObj
    }).filter(val => { return val.url })
   }
  },
  handleRemove(file, fileList) {
   this.getElement(fileList.length)
  },
  handlePictureCardPreview(file) {
   this.dialogImageUrl = file.url
   this.dialogVisible = true
  },
  handleProgress(event, file, fileList) {
   this.percentage = +file.percentage
  },
  fileBeforeUpload(file, event) {
   if (this.acceptType === 'image' && !file.type.includes('image/')) {
    this.$warning('请上传图片')
    return false
   }
   if (this.acceptType === 'video' && !file.type.includes('video/')) {
    this.$warning('请上传视频')
    return false
   }
   this.isUpload = true
   if (file.type.includes('image/') && (file.size > this.maxSize * 1024 * 1024)) {
    this.$warning(`请上传小于${this.maxSize}M的图片`)
    this.percentage = 0
    this.isLoading = false
    return false
   }
   if (file.type.includes('video/')) this.isDiabled = true
   if (this.isCropper) {
    return false
   }
  },
  fileChange(file, fileList) {
   if (file.percentage === 0 && this.isCropper) {
    if (file.raw.type.includes('video/')) {
     this.$warning('请上传图片')
     return
    }
    this.imgSrc = file.url
    this.modifyCropper = true
    this.cropperImage = {
     coverUrl: '',
     isImg: true,
     isPlay: true,
     name: file.name
    }
   }
  },
  // 实时预览函数
  realTime(data) {
   this.previews = data
  },
  imgLoad(data) {
  },
  // 裁剪后上传图片
  uploadCropperImage() {
   const _this = this
   this.$refs.cropper.getCropBlob((data) => {
    const config = {
     headers: {
      'Authorization': _this.headers.Authorization,
      'Content-Type': 'multipart/form-data'
     }
    }
    const formdata = new FormData()
    formdata.append('file', data)
    // this.uploadUrl 上传
    axios.post(this.uploadUrl, formdata, config).then(response => {
     _this.cropperImage = Object.assign({}, _this.cropperImage, {
      displayUrl: response.data.data,
      url: response.data.data,
      id: Date.now()
     })
     _this.draggableList.push(_this.cropperImage)
     _this.$emit('getImageList', _this.draggableList.map(val => {
      if (this.returnType === 'Array') {
       return val.url
      }
      if (this.returnType === 'Object') {
       return {
        url: val.url,
        uploadStatus: true
       }
      }
     }), _this.customObject)
     _this.modifyCropper = false
    }).catch(error => {
     console.log('err', error)
    })
   })
  },
  imageSuccess(response, file, fileList) {
   const _this = this
   try {
    this.getElement(fileList.length)
    let displayUrl = ''
    let coverUrl = ''
    let isImg = true
    const url = file.response.data || file.url
    this.isUpload = false
    const files = url.split(',')
    if (files.length === 3) {
     displayUrl = files[1]
     coverUrl = files[2]
     isImg = false
    } else if (files.length === 1) {
     displayUrl = url
     isImg = true
    }
    const id = Date.now()
    _this.draggableList.push({
     name: file.name,
     url: url,
     coverUrl: coverUrl,
     displayUrl: displayUrl,
     isImg: isImg,
     isPlay: true,
     id: id
    })
    if (isImg) {
     _this.percentage = 0
     _this.$emit('getImageList', _this.draggableList.map(val => {
      if (this.returnType === 'Array') {
       return val.url
      }
      if (this.returnType === 'Object') {
       return {
        url: val.url,
        uploadStatus: true
       }
      }
     }), _this.customObject)
     return
    }
    _this.$emit('getImageList', _this.draggableList.map(val => {
     if (this.returnType === 'Array') {
      return val.url
     }
     if (this.returnType === 'Object') {
      return {
       url: val.url,
       uploadStatus: false
      }
     }
    }), _this.customObject)
    setTimeout(() => {
     const keys = Object.keys(_this.$refs)
     const video = _this.$refs[`${keys[keys.length - 1]}`][0]
     const removeId = keys[keys.length - 1]
     const interval = setInterval(() => {
      if (video.readyState === 4) {
       const duration = video.duration
       this.isDiabled = false
       if (duration < 3 || duration > 60) {
        _this.$message.success('请上传大于三秒小于六十秒的视频')
        _this.percentage = 0
        // _this.remove(_this.draggableList.length - 1)
        _this.draggableList = _this.draggableList.filter(val => {
         return (val.id + '') !== (removeId + '')
        })
        _this.$emit('getImageList', _this.draggableList.map(val => {
         if (this.returnType === 'Array') {
          return val.url
         }
         if (this.returnType === 'Object') {
          return {
           url: val.url,
           uploadStatus: true
          }
         }
        }), _this.customObject)
        _this.getElement(_this.draggableList.length)
       }
       _this.percentage = 0
       _this.$emit('getImageList', _this.draggableList.map(val => {
        if (this.returnType === 'Array') {
         return val.url
        }
        if (this.returnType === 'Object') {
         return {
          url: val.url,
          uploadStatus: true
         }
        }
       }), _this.customObject)
       clearInterval(interval)
      }
      video.src = displayUrl
      video.poster = coverUrl
     }, 1000)
    }, 1000)
   } catch (error) {
    console.log('error', error)
   }
  },
  play(item) {
   const video = document.getElementById(item.id)
   video.play()
   item.isPlay = !item.isPlay
  },
  pause(item) {
   const video = document.getElementById(item.id)
   video.pause()
   item.isPlay = !item.isPlay
  },
  // 全屏播放
  fullPlay(item) {
   const video = document.getElementById(item.id)
   // w3c
   typeof video.requestFullScreen === 'function' && video.requestFullScreen()
   // webkit(谷歌)
   typeof video.webkitRequestFullScreen === 'function' && video.webkitRequestFullScreen()
   // 火狐
   typeof video.mozRequestFullScreen === 'function' && video.mozRequestFullScreen()
   // IE
   typeof video.msExitFullscreen === 'function' && video.msExitFullscreen()
  },
  viewImage(url) {
   this.dialogImageUrl = url
   this.dialogVisible = true
  },
  remove(index) {
   this.draggableList.splice(index, 1)
   this.$emit('getImageList', this.draggableList.map(val => {
    if (this.returnType === 'Array') {
     return val.url
    }
    if (this.returnType === 'Object') {
     return {
      url: val.url,
      uploadStatus: true
     }
    }
   }), this.customObject)
   this.getElement(this.draggableList.length)
  },
  onEnd(event) {
   this.$emit('getImageList', this.draggableList.map(val => {
    if (this.returnType === 'Array') {
     return val.url
    }
    if (this.returnType === 'Object') {
     return {
      url: val.url,
      uploadStatus: true
     }
    }
   }), this.customObject)
  },
  isImg(obj) {
   const item = obj.url
   if (item === '' || item === null || typeof item === 'undefined') {
    return false
   }
   const index = item.lastIndexOf('.')
   var ext = item.substr(index + 1)
   if (ext.includes('!')) ext = ext.split('!')[0]
   ext = ext.toLowerCase()
   var tps = ['jpg', 'jpeg', 'png']
   let ok = false
   for (let i = 0; i < tps.length; i++) {
    if (tps[i] === ext) {
     ok = true
     break
    }
   }
   return ok
  },
  getElement(length) {
   const _this = this
   if (length >= _this.maxNum) {
    document.querySelectorAll(`#${_this.uploadId} .el-upload--picture-card`).forEach(val => {
     if (val.firstElementChild.className === 'el-icon-plus') {
      val.style.display = 'none'
      return true
     }
    })
   } else {
    document.querySelectorAll(`#${_this.uploadId} .el-upload--picture-card`).forEach(val => {
     if (val.firstElementChild.className === 'el-icon-plus') {
      val.style.display = 'inline-block'
      return true
     }
    })
   }
  }
 }
}

</script>
<style lang='scss' scoped>
.image-draggable {
  display: flex;
  flex-wrap: wrap;
  .image-list {
    position: relative;

    display: inline-block;
    overflow: hidden;

    width: 148px;
    height: 148px;
    margin-right: 10px;

    cursor: pointer;
    &:hover {
      .icon {
        height: 20%;

        transition: all .5s;
        .video-icon {
          display: inline-block;

          margin-right: 10px;
        }
      }
    }
    .icon {
      position: absolute;
      bottom: 0;

      display: flex;
      justify-content: center;

      width: 100%;
      height: 0;

      background-color: rgba(215, 215, 215, 1);
      .icon-size {
        width: 2em;
        height: 2em;
      }
      .video-icon {
        display: none;
      }
    }
  }
}
</style>
<style lang="scss">
.image-draggable {
  .el-progress {
    top: -50%;
  }
}
</style>

注册全局事件

创建eventBus.js

vue3.0 搭建项目总结(详细步骤)

使用

import eventBus from './plugins/eventBus'
Vue.use(eventBus)

处理缓存

借用mounted, activated 事件处理数据

在某一次打开页面的时候进行数据初始化存储, 放置在vuex中,或者全局变量中,当需要初始化进行一个初始化,采取mixins引入

vue3.0 搭建项目总结(详细步骤)

vue3.0 搭建项目总结(详细步骤)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
ImageFlow可鼠标控制图片滚动
Jan 30 Javascript
jQuery Div中加载其他页面的实现代码
Feb 27 Javascript
js 禁用只读文本框获得焦点时的退格键
Apr 25 Javascript
JavaScript高级程序设计(第3版)学习笔记 概述
Oct 11 Javascript
js模仿微信朋友圈计算时间显示几天/几小时/几分钟/几秒之前
Apr 27 Javascript
详谈for循环里面的break和continue语句
Jul 20 Javascript
Nuxt升级2.0.0时出现的问题(小结)
Oct 08 Javascript
JSON.stringify()方法讲解
Jan 31 Javascript
node实现mock-plugin中间件的方法
Dec 25 Javascript
解决vue项目input输入框双向绑定数据不实时生效问题
Aug 05 Javascript
关于Vue中$refs的探索浅析
Nov 05 Javascript
原生js实现放大镜组件
Jan 22 Javascript
vue-cli webpack配置文件分析
May 20 #Javascript
微信小程序开发之左右分栏效果的实例代码
May 20 #Javascript
微信小程序rich-text富文本用法实例分析
May 20 #Javascript
bootstrap中的导航条实例代码详解
May 20 #Javascript
详解小程序云开发数据库
May 20 #Javascript
VUE脚手架具体使用方法
May 20 #Javascript
Vue CLI2升级至Vue CLI3的方法步骤
May 20 #Javascript
You might like
PHP设计模式 注册表模式
2012/02/05 PHP
php 类中的常量、静态属性、非静态属性的区别
2017/04/09 PHP
PHP流Streams、包装器wrapper概念与用法实例详解
2017/11/17 PHP
经验几则 推荐
2006/09/05 Javascript
javascript十个最常用的自定义函数(中文版)
2009/09/07 Javascript
基于jquery的图片懒加载js
2010/06/30 Javascript
Jquery中显示隐藏的实现代码分析
2011/07/26 Javascript
js冒泡、捕获事件及阻止冒泡方法详细总结
2014/05/08 Javascript
javascript 中that的含义示例介绍
2014/05/14 Javascript
Jquery弹出层插件ThickBox的使用方法
2014/12/09 Javascript
JavaScript仿支付宝密码输入框
2015/12/29 Javascript
详解plotly.js 绘图库入门使用教程
2018/02/23 Javascript
微信小程序实现指定显示行数多余文字去掉用省略号代替
2018/07/25 Javascript
webpack4.x开发环境配置详解
2018/08/04 Javascript
JSON基本语法及与JavaScript的异同实例分析
2019/01/04 Javascript
vuejs数据超出单行显示更多,点击展开剩余数据实例
2019/05/05 Javascript
ant design vue datepicker日期选择器中文化操作
2020/10/28 Javascript
[47:42]完美世界DOTA2联赛PWL S2 GXR vs Ink 第一场 11.19
2020/11/20 DOTA
python的dict,set,list,tuple应用详解
2014/07/24 Python
Python中getattr函数和hasattr函数作用详解
2016/06/14 Python
Python、PyCharm安装及使用方法(Mac版)详解
2017/04/28 Python
linux查找当前python解释器的位置方法
2019/02/20 Python
深入浅析python 协程与go协程的区别
2019/05/09 Python
如何基于Django实现上下文章跳转
2020/09/16 Python
css3圆角边框和边框阴影示例
2014/05/05 HTML / CSS
德国知名健康零食网上商店:Seeberger
2017/07/27 全球购物
C#如何调用Windows程序打开一个文档
2014/12/26 面试题
行政工作试用期自我评价
2014/09/14 职场文书
庆祝国庆节标语
2014/10/09 职场文书
2014年学习部工作总结
2014/11/12 职场文书
读完《骆驼祥子》的观后感!
2019/07/05 职场文书
2019年共青团工作条例最新版
2019/11/12 职场文书
nginx优化的六点方法
2021/03/31 Servers
解决MySQL添加新用户-ERROR 1045 (28000)的问题
2022/03/03 MySQL
Win11 BitLocker 驱动器加密
2022/04/19 数码科技
python如何利用cv2.rectangle()绘制矩形框
2022/12/24 Python