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 相关文章推荐
javascript 继承实现方法
Aug 26 Javascript
JS中令人发指的valueOf方法介绍
Feb 22 Javascript
javascript 用函数语句和表达式定义函数的区别详解
Jan 06 Javascript
使用jQuery实现图片遮罩半透明坠落遮挡
Mar 16 Javascript
简单实现js浮动框
Dec 13 Javascript
js正则表达式验证表单【完整版】
Mar 06 Javascript
JavaScript使用链式方法封装jQuery中CSS()方法示例
Apr 07 jQuery
vue获取input输入值的问题解决办法
Oct 17 Javascript
angularJs复选框checkbox选中进行ng-show显示隐藏的方法
Oct 08 Javascript
使用Vue.js中的过滤器实现幂方求值的方法
Aug 27 Javascript
解决Can't find variable: SockJS vue项目的问题
Sep 22 Javascript
js实现简易点击切换显示或隐藏
Nov 29 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提取中英文词语以及数字的首字母的方法介绍
2013/04/23 PHP
php安装xdebug/php安装pear/phpunit详解步骤(图)
2013/12/22 PHP
PHP异常处理Exception类
2015/12/11 PHP
javascript 中that的含义示例介绍
2014/05/14 Javascript
jquery的clone方法应用于textarea和select的bug修复
2014/06/26 Javascript
浅谈JavaScript Date日期和时间对象
2014/12/29 Javascript
javascript实现对表格元素进行排序操作
2015/11/18 Javascript
JavaScript遍历求解数独问题的主要思路小结
2016/06/12 Javascript
用js实现before和after伪类的样式修改的示例代码
2017/09/07 Javascript
从vue源码解析Vue.set()和this.$set()
2018/08/30 Javascript
vue 解决循环引用组件报错的问题
2018/09/06 Javascript
vue-router传递参数的几种方式实例详解
2018/11/13 Javascript
js实现表单项的全选、反选及删除操作示例
2020/06/05 Javascript
viewer.js实现图片预览功能
2020/06/24 Javascript
python使用datetime模块计算各种时间间隔的方法
2015/03/24 Python
Python根据区号生成手机号码的方法
2015/07/08 Python
详解python异步编程之asyncio(百万并发)
2018/07/07 Python
python整合ffmpeg实现视频文件的批量转换
2019/05/31 Python
Python实现的统计文章单词次数功能示例
2019/07/08 Python
python绘制雪景图
2019/12/16 Python
基于python使用tibco ems代码实例
2019/12/20 Python
Python使用re模块验证危险字符
2020/05/21 Python
详解查看Python解释器路径的两种方式
2020/10/15 Python
日本最大的眼镜购物网站:Oh My Glasses
2016/11/13 全球购物
森海塞尔美国官网:Sennheiser耳机与耳麦
2017/07/19 全球购物
医学专业毕业生个人求职信
2013/12/25 职场文书
预备党员思想汇报
2014/01/08 职场文书
最新的互联网创业计划书
2014/01/10 职场文书
优秀党员获奖感言
2014/02/18 职场文书
质量月口号
2014/06/20 职场文书
合唱兴趣小组活动总结
2014/07/10 职场文书
社团个人总结范文
2015/03/05 职场文书
毕业设计论文致谢词
2015/05/14 职场文书
证婚人婚礼致辞
2015/07/28 职场文书
《唯一的听众》教学反思
2016/02/18 职场文书
Javascript设计模式之原型模式详细
2021/10/05 Javascript