送给萌新的Vue/JS的拷贝大法

前言

常常看到群里有萌新提问element相关使用问题,其实官方文档很详细了,但为了照顾萌新们,因此本篇文章就把常见的业务代码直接抛出来给萌新们直接无门槛使用!javascript

element 动态面包屑

bread.vuecss

<template>
  <div class="bread">
     <el-breadcrumb class="breadcrumb" separator="/">
            <el-breadcrumb-item v-for='(item,index) of list' :key='index' v-if='item.name'>
                <i class="iconfont" :class="item.meta.icon"></i>
				{{item.name}}
			</el-breadcrumb-item>
    </el-breadcrumb>
  </div>
</template>

<script> export default { name: '', data () { return { list: null, icon:[] } }, created () { this.getBreadcrumb(); }, methods: { getBreadcrumb () { this.icon= JSON.parse(sessionStorage.getItem('menu')) let matched = this.$route.matched.filter(item => item.name); const first = matched[0]; this.list = matched; this.erpName = sessionStorage.getItem('erpName') } }, watch: { $route() { this.getBreadcrumb(); } } } </script>

<style lang="less" scoped> .bread { background-color: #fff; padding: 15px; margin: 10px 0; } </style>
复制代码

vue-awesome-swiper 轮播图效果

<!-- 轮播图开始 -->
<div class="swiper">
  <swiper :options="swiperOption" class="banner">
    <swiper-slide v-for="(item, index) in bannerImg" :key="index"><img :src="item"></swiper-slide>
  </swiper>
</div>
<!-- 轮播图结束 -->
复制代码
import {swiper, swiperSlide} from 'vue-awesome-swiper'
export default {
  data() {
    return {
      swiperOption: {
        initialSlide: 1,
        autoplay: {
          delay: 3000,
          stopOnLastSlide: false,
          disableOnInteraction: false,
        },
        autoplayDisableOnInteraction: true,
        loop: true,
        slidesPerView: "auto",
        centeredSlides: true
      }
    }
  },
  components: {
    swiper,
    swiperSlide,
  }
}
复制代码
.swiper
    width: 100%
    height: px2rem(130px)
    margin-top: px2rem(10px)
    overflow: hidden
    .swiper-slide
      display: inline-block
      width: 80%;
      height: px2rem(130px)
      &.swiper-slide-active
        img
          margin-top: 0
          width: 100%
          height: 100%
      img
        display: block
        margin: 0 auto
        margin-top: 3.5%
        width: 90.625%
        height: 90.625%
        border-radius: 4px
        vertical-align: middle
复制代码

vue 自定义上传头像

<div @click.native="handleUpload">上传</div>

  <!-- 调用相机/图库 -->
  <input type="file" accept="image/*" @change="handleFileChanged" ref="file" hidden>
  <input type="file" accept="image/*" capture="camera" @change="handleFileChanged" ref="camera" hidden>

  <!-- 修改头像开始 -->
    <mt-popup v-model="avatarShow" position="bottom" popup-transition="popup-fade" class="gender upload">
      <div class="item red" @click="handleCamera()">拍照</div>
      <div class="item" @click="handleImgUpload()">从相册里选择</div>
      <div class="item btn" @click="avatarShow=false">取消</div>
    </mt-popup>
  <!-- 修改头像结束 -->
复制代码
import uuid from'uuid'
 export default {
   data() {
     return {
        token: '',
        name: '',
        avatar: '',
        avatarShow: false,
        files: [],
     }
   },
   methods: {
      handleUpload() {
        this.avatarShow = true
      },
      handleImgUpload() { // 调用相片
        this.files= []
        this.$refs.file.click()
        this.avatarShow = false
      },
      handleCamera() { // 调用相机
        this.files= []
        this.$refs.camera.click()
        this.avatarShow = false
      },
      handleFileChanged($event) {
        let file = $event.target.files[0]
        const freader = new FileReader()
        freader.readAsDataURL(file)
        this.files.push(file)
        freader.onload = (e) => {
          this.files.push({
            src: e.target.result
          })
        }

        let formData = new FormData()
        formData.append('file', file)
        formData.append('key', `${this.name+uuid.v4() + '.' + file.type.split('/')[1]}`)
        formData.append('token', this.token)
        let data = this.$axios.post('https://upload.qbox.me', formData, {
          headers: {
            'Content-Type': 'multipart/form-data',
          }
        })
         data.then(res=>{
          this.avatar = res.key
          this.uploadAvatar()
        })
      },
      getToken () { // 获取七牛token
        this.$axios.get('api-f/qiniu/uploadToken/4').then((res) => {
          this.token = res.result[0].qiniuToken
          this.name = res.result[0].name
        })
      },
   }
 }
复制代码

vue element中table 序号累计

<el-table :data="billData" class="table" stripe>
    <el-table-column align="center" type="index" :index="getIndex" width="50" label="#" />
 </el-table>
复制代码
export default {
  data() {
    return {
      searchParamas: {
        total: 0,
        pageNum: 1,
        pageSize: 10
      },
    }
  },
  methods: {
    getIndex(index) {
      return index + (this.searchParamas.pageNum - 1) * 10 + 1
    },
  }
}
复制代码

vue移动端适配

index.html加上html

<meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no,viewport-fit=cover">
复制代码

安装依赖vue

npm install lib-flexible
复制代码

main.js引入:java

import 'lib-flexible'
复制代码

postcss.config.js配置:node

module.exports = {
  "plugins": {
    "postcss-import": {},
    "postcss-url": {},
    "postcss-aspect-ratio-mini": {},
    "postcss-write-svg": { utf8: false },
    "postcss-cssnext": {},
    "postcss-px-to-viewport": {
      viewportWidth: 750, // 视窗的宽度,对应的是咱们设计稿的宽度,通常是750
      viewportHeight: 1334, // 视窗的高度,根据750设备的宽度来指定,通常指定1334,也能够不配置
      unitPrecision: 3,  // 指定`px`转换为视窗单位值的小数位数(不少时候没法整除)
      viewportUnit: 'vw',  // 指定须要转换成的视窗单位,建议使用vw
      selectorBlackList: ['.ignore', '.hairlines'], // 指定不转换为视窗单位的类,能够自定义,能够无限添加,建议定义一至两个通用的类名
      minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也能够设置为你想要的值
      mediaQuery: false // 容许在媒体查询中转换`px`
    },
    "postcss-viewport-units": {},
  }
}

复制代码

vue-router 路由拦截

一、to: Route: 即将要进入的目标 路由对象webpack

二、from: Route: 当前导航正要离开的路由ios

三、next: Function: 必定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。web

四、next(): 进行管道中的下一个钩子。若是所有钩子执行完了,则导航的状态就是 confirmed (确认的)。vue-router

五、next(false): 中断当前的导航。若是浏览器的 URL 改变了(多是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

六、next('/') 或者 next({ path: '/' }): 跳转到一个不一样的地址。当前的导航被中断,而后进行一个新的导航

//router.js
router.beforeEach((to, from, next) => {
  if (to.meta.requireAuth) {
    // 判断该路由是否须要登陆权限
    if (store.state.token) {
      // 经过vuex state获取当前的token是否存在
      next();
    } else {
      next({
        path: "/login",
        query: { redirect: to.fullPath } // 将跳转的路由path做为参数,登陆成功后跳转到该路由
      });
    }
  } else {
    next();
  }
});
复制代码

npm经常使用包大全

vue-lazyload 图片懒加载,功能很全

axios

支持 promise 的 http 库

amfe-flexible

移动端适配

vue-meta

组件中动态修改 head 标签里面的内容

webpack-bundle-analyzer

打包完成后显示体积相关信息,能够了解是否重复加载,哪些文件过大等

html-webpack-include-assets-plugin

用于添加 js 或 css 文件路径

vue-awesome-swiper

移动端轮播图插件

swiper.animate1.0.3.min.js

动画过渡插件

vue-wechat-title

微信动态设置标题

uuid

生成 uid(惟一标识符)

md5

md5 加密

weixin-js-sdk

微信的 jssdk 库(微信分享)

nodemon

用 nodemon 来代替 node 来启动应用

babel-polyfill

IE9 不支持 Promise,需安装 babel-polyfill

qs

数据格式转换插件,配合 axios 使用

vue-contextmenu

右键弹出菜单插件

vue-touch

装了 hammer.js 的方法

vuex-persistedstate

vuex 数据持久化

vconsole

手机端调试 console

vue-pano

全景图插件

better-scroll

滚动插件

vue-amap

高德地图

页面顶部进度条

nprogress

core-decorators / babel-plugin-transform-decorators-legacy

装饰器

vue微信分享封装

import api from './api'
import wx from 'weixin-js-sdk'
**
 *分享
 * @param self
 * @param title 标题
 * @param url 连接
 * @param img 图片
 * @param desc 描述
 */

export const wxShare = (self, title, url, img, desc) => {
  let url = window.location.href;
  let data = {
    url: url
  };
  api(data).then(res => {
    if (res.code === 1) {
      let data = res.data;
      wx.config({
        debug: false, // 开启调试模式,调用的全部api的返回值会在客户端alert出来,若要查看传入的参数,能够在pc端打开,参数信息会经过log打出,仅在pc端时才会打印。
        appId: data.appId, // 必填,公众号的惟一标识
        timestamp: data.timestamp, // 必填,生成签名的时间戳
        nonceStr: data.nonceStr, // 必填,生成签名的随机串
        signature: data.signature, // 必填,签名,见附录1
        jsApiList: ["onMenuShareTimeline", "onMenuShareAppMessage"] // 必填,须要使用的JS接口列表,全部JS接口列表见附录2
      });
      wx.ready(function () {
        wx.onMenuShareTimeline({
          title: title, // 分享标题
          link: url, // 分享连接,该连接域名或路径必须与当前页面对应的公众号JS安全域名一致
          imgUrl: img, // 分享图标
          success: function () {
            // 用户确认分享后执行的回调函数
            self.$toast('分享成功!!!');
          },
          cancel: function () {
            // 用户取消分享后执行的回调函数
            self.$toast('取消分享!!!');
          }
        });
        wx.onMenuShareAppMessage({
          title: title, // 分享标题
          desc: desc, // 分享描述
          link: url, // 分享连接,该连接域名或路径必须与当前页面对应的公众号JS安全域名一致
          imgUrl: img, // 分享图标
          type: "", // 分享类型,music、video或link,不填默认为link
          dataUrl: "", // 若是type是music或video,则要提供数据连接,默认为空
          success: function () {
            // 用户确认分享后执行的回调函数
            self.$toast('分享成功!!!');
          },
          cancel: function () {
            // 用户取消分享后执行的回调函数
            self.$toast('取消分享!!!');
          }
        });
      });
    }
  }).catch(err => {
    console.log(err)
  })
};
复制代码

vue 自动注册全局组件

/** * 读取componetns下的vue文件并自动注册全局组件 */
const requireComponent = require.context('./components', false, /\.vue$/)

requireComponent.keys().forEach(fileName => {

 const componentConfig = requireComponent(fileName)
 const componentName = fileName.replace(/^\.\//, '').replace(/\.vue/, '')

 Vue.component(componentName, componentConfig.default || componentConfig)
})

/** * 读取./modules下的全部js文件并注册模块 */
const requireModule = require.context('./modules', false, /\.js$/)
const modules = {}

requireModule.keys().forEach(fileName => {
 const moduleName = fileName.replace(/(\.\/|\.js)/g, '')
 modules[moduleName] = {
  namespaced: true,
  ...requireModule(fileName).default
 }
})

export default modules

//main.js 文件
import components from './components'
Object.keys(components).forEach((component) => {
  Vue.component(component, components[component])
})
复制代码

vue+element修改表头颜色

<el-table :data="tableData" border :header-cell-style="getRowClass">
复制代码
getRowClass({ row, column, rowIndex, columnIndex }) {
  if (rowIndex === 0) {
    return 'background:#F9F9F9'
  } else {
    return ''
  }
}
复制代码

vue filter 全局封装

//filter.js
let _filters = {};
/** * 金额转化 * @param 金额 */
_filters.money = num => {
  return num ? `¥${num}` : '';
};
/** 格式化时间 * @param {string} date 须要格式化的时间 * @param {string} fmt 想要格式化的格式 yyyy-MM-dd yyyy-MM-dd hh:mm:ss */
_filters.formatDate = (date, fmt = 'yyyy-MM-dd') => {
  let o = {
    'M+': date.getMonth() + 1, //月份
    'd+': date.getDate(), //日
    'h+': date.getHours(), //小时
    'm+': date.getMinutes(), //分
    's+': date.getSeconds(), //秒
    'q+': Math.floor((date.getMonth() + 3) / 3), //季度
    S: date.getMilliseconds() //毫秒
  };
  if (/(y+)/.test(fmt))
    fmt = fmt.replace(
      RegExp.$1,
      (date.getFullYear() + '').substr(4 - RegExp.$1.length)
    );
  for (var k in o)
    if (new RegExp('(' + k + ')').test(fmt))
      fmt = fmt.replace(
        RegExp.$1,
        RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
      );
  return fmt;
};

_filters.formatTime(time, option) {
  time = +time * 1000
  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() + '分'
  }
}

_filters.parseTime(time, cFormat) {
  if (arguments.length === 0) {
    return null
  }

  if ((time + '').length === 10) {
    time = +time * 1000
  }

  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    date = new Date(parseInt(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(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    let value = formatObj[key]
    if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
    if (result.length > 0 && value < 10) {
      value = '0' + value
    }
    return value || 0
  })
  return time_str
}
export default Vue => {
  Object.keys(_filters).forEach(key => {
    vue.filter(key, _filters[key]);
  });
};
//main.js
import filters from './filter';
Vue.use(filters);
复制代码

vue excel 二进制文件下载

this.$axios
  .get(`xxx`, {
    responseType: 'blob'
  })
  .then(res => {
    let blob = new Blob([res])
    const fileName = '库存票据.xls'
    if ('download' in document.createElement('a')) {
      // 非IE下载
      const elink = document.createElement('a')
      elink.download = fileName
      elink.style.display = 'none'
      elink.href = URL.createObjectURL(blob)
      document.body.appendChild(elink)
      elink.click()
      URL.revokeObjectURL(elink.href) // 释放URL 对象
      document.body.removeChild(elink)
    } else {
      // IE10+下载
      navigator.msSaveBlob(blob, fileName)
    }
  })
复制代码

vue 验证码上一个/下一个焦点的获取

<template>
  <div>
    <label for=""><span class="tip">*</span>{{label}}</label>
    <template v-for="i of num" >
      <input type="number" :key="i" @input="maxlength" @keyup="getCode" class="input" :class="classes">
    </template>
  </div>
</template>
复制代码
export default {
    model: {
      prop: 'value',
      event: 'getValue'
    },
    props: {
      value: {
        type: [Number, String]
      },
      type: { // 类型
        type: String,
        default: 'text' // text与passw两种类型
      },
      num: {
        type: Number,
        default: 6
      },
      label: {
        type: String,
      },
      clear: { // 清空值
        type: Boolean,
        default: false
      }
    },
    data() {
      return {
        arrVal: []
      };
    },
    computed: {
      classes() {
        return this.type === 'password' ? 'point' : '';
      }
    },
    methods: {
      maxlength(e) {
        if (e.target.value.length > 1) {
          e.target.value = e.target.value.slice(0, 1);
        }
      },
      getCode(el) {
        const dom = el.target;
        const nexDom = dom.nextElementSibling;
        if (!/^\d$/.test(dom.value)) {
          dom.value = '';
        }
        if (dom.value) {
          if (this.arrVal.length < this.num) {
            this.arrVal.push(dom.value);
          }
          if (nexDom) {
            nexDom.focus();
          }
        }
        if (el.keyCode === 8 && dom.previousElementSibling) {
          this.arrVal.pop();
          dom.previousElementSibling.focus();
        }
        const strValue = this.arrVal.join('');
        this.$emit('getValue', strValue);
      }
    },
    watch: {
      clear(n) {
        if (n) {
          const dom = this.$refs.input;
          dom.map(item => {
            item.value = '';
          });
        }
      }
    }
  };
复制代码
.point{
  -webkit-text-security:disc;
  text-security: disc;
  font-size: 24px;
}
复制代码

使用:

<zy-input type="password" v-model="pwd" label="请输入支付密码:"></zy-input>
复制代码

vue element使用select作模糊搜索

<el-form-item label="所属企业:">
  <el-select class="input" v-model="form.companyName" filterable @change="getCurrentData($event)" clearable @keyup.native="getUnitList($event)" placeholder="请选择">
    <el-option v-for="item of company" :key="item.id" :label="item.companyName" :value="item.id">
    </el-option>
  </el-select>
</el-form-item>
复制代码
export default {
  data() {
    return {
      currentCompany: {},
      company: [],
    }
  },
  methods: {
    getCurrentData(id) { // 获取当前选中对象
      this.form.companyId = id
      this.currentCompany = this.company.find(item => item.id === id)
    },
    async getUnitList(el) {
      const res = await this.$apis.getUnitList({
        pageNum: 1,
        pageSize: 10,
        companyName: el.target.value
      })
      if(res.code===1) {
        this.company = res.data
      }
    },
  }
}
复制代码

vue pdf 文件下载

<template>
  <div class="priview_resume_container">
    <div style="font-size: 30px" @click="getResume">点这里下载</div>
  </div>
</template>
复制代码
<script>
  export default {
    name: 'priviewResume',
    methods: {
      getResume() {
        this.commonUtils.generateResume(
          $('.priview_resume_container')[0],
          '测试'
        )
      }
    },
    components: {}
  }
</script>
复制代码
import html2canvas from 'html2canvas'
import JsPDF from 'jspdf'
export const generateResume = (el, name) => {
  html2canvas(el).then(canvas => {
    let contentWidth = canvas.width
    let contentHeight = canvas.height
    //一页pdf显示html页面生成的canvas高度;
    let pageHeight = (contentWidth / 592.28) * 841.89
    //未生成pdf的html页面高度
    let leftHeight = contentHeight
    //页面偏移
    let position = 0
    //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
    let imgWidth = 595.28
    let imgHeight = (592.28 / contentWidth) * contentHeight
    let pageData = canvas.toDataURL('image/jpeg', 1.0)
    let pdf = new JsPDF('', 'pt', 'a4')
    //有两个高度须要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
    //当内容未超过pdf一页显示的范围,无需分页
    if (leftHeight < pageHeight) {
      pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
    } else {
      while (leftHeight > 0) {
        //arg3-->距离左边距;arg4-->距离上边距;arg5-->宽度;arg6-->高度
        pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
        leftHeight -= pageHeight
        position -= 841.89
        //避免添加空白页
        if (leftHeight > 0) {
          //添加新页
          pdf.addPage()
        }
      }
    }
    pdf.save(`${name}.pdf`)
  })
}
复制代码

vue 监听鼠标滚轮方向

Vue.directive('scroll', {
  // 当绑定元素插入到 DOM 中
  inserted: function (el,binding) {
    var cb = binding.value
    el.addEventListener('mousewheel',function(e){
      var direction = e.deltaY>0?'down':'up'
      cb(direction)
    })
  }
})

<div v-scroll="fn">
复制代码

vue 局部刷新组件

<template>
  <div id="app">
    <router-view  v-if="isRouterActive"/>
  </div>
</template>

<script>
export default {
  name: 'App',
  provide() {
    return {
      reload: this.reload
    }
  },
  data() {
    return {
      isRouterActive: true
    }
  },
  methods: {
    reload() {
      this.isRouterActive = false
      this.$nextTick(() => {
        this.isRouterActive = true
      })
    }
  },
}
</script>
复制代码
<template>
  <div> <div class="item" v-for="item of num" :key="item">{{item}}</div> <el-button @click="add">添加</el-button> <el-button @click="refresh">刷新</el-button> </div> </template> <script> export default { inject: ['reload'], data() { return { num: 0 } }, methods: { refresh() { this.reload() }, add() { this.num = 6 } }, } </script> 复制代码

vue input file上传文件后清空

<form ref="form">
  <input type="file" @change="uploadFile" />
</form>
复制代码
// 文件上传成功后
this.$refs.form.reset()
复制代码

vue 自定义注册全局函数

/**
 * 付款方状态
 */
const PAYER_STATUS = {

};
/**
 * 收款方状态
 */
const PAYEE_STATUS = {

};

export const status = {
  PAYER_STATUS,
  PAYEE_STATUS,
  install(Vue) {
    Vue.prototype.$status = this;
  }
}

//main.js
Vue.use(status);
复制代码

vue element 表格复选框禁止

<el-table-column type="selection" :selectable="disableCheckbox" width="55">
</el-table-column>
复制代码
export default {
  methods: {
    disableCheckbox(row, index) {
      if (row.businessStatus === 4 || row.businessStatus === 6) {
        return false
      } else {
        return true
      }
    }
  }
}
复制代码

vue vue-quill-editor 富文本

//main.js
import VueQuillEditor from 'vue-quill-editor'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor /* { default global options } */)
复制代码
//组件使用
<template>
  <div>
    <quill-editor
      v-model="form.content"
      ref="myQuillEditor"
      :options="editorOption"
      @change="onEditorChange"
      @blur="onEditorBlur($event)"
      @focus="onEditorFocus($event)"
      @ready="onEditorReady($event)"
    >
    </quill-editor>
    <!-- 上传图片 -->
    <el-upload
      class="avatar-uploader"
      action=""
      multiple
      ref="uploadImage"
      accept="image/*"
      :http-request="uploadImage"
      style="display:none"
    >
      <el-button
        size="small"
        type="primary"
        id="imgInput"
        v-loading.fullscreen.lock="fullscreenLoading"
        element-loading-text="插入中,请稍候"
        >点击上传</el-button
      >
    </el-upload>
    <!-- 上传视频 -->
    <el-dialog
      :show-close="false"
      append-to-body
      title="上传视频"
      :visible.sync="dialogVisible"
      center
      width="40%"
    >
      <div class="upload-content">
        <el-upload
          drag
          accept="video/*"
          ref="video"
          action=""
          :http-request="uploadVideo"
        >
          <i class="el-icon-upload"></i>
          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        </el-upload>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="upload">确 定</el-button>
      </span>
    </el-dialog>
  </div>
  <script>
    const toolOptions = [
      ['bold', 'italic', 'underline', 'strike'],
      ['blockquote', 'code-block'],
      [{ header: 1 }, { header: 2 }],
      [{ list: 'ordered' }, { list: 'bullet' }],
      [{ script: 'sub' }, { script: 'super' }],
      [{ indent: '-1' }, { indent: '+1' }],
      [{ direction: 'rtl' }],
      [{ size: ['small', false, 'large', 'huge'] }],
      [{ header: [1, 2, 3, 4, 5, 6, false] }],
      [{ color: [] }, { background: [] }],
      [{ font: [] }],
      [{ align: [] }],
      [{ clean: '源码编辑' }],
      ['link', 'image', 'video'],
      ['sourceEditor'] //新添加的工具
    ]
    export default {
      data() {
        const self = this
        return {
          fullscreenLoading: false,
          editorOption: {
            placeholder: '',
            theme: 'snow', // 主题
            modules: {
              toolbar: {
                container: toolOptions, // 工具栏选项
                handlers: {
                  video: val => {
                    self.dialogVisible = true
                  },
                  image: val => {
                    document.querySelector('.avatar-uploader input').click()
                    console.log(val)
                  }
                } // 事件重写
              }
            }
          }
        }
      },
      computed: {
        editor() {
          return this.$refs.myQuillEditor.quill
        }
      },
      methods: {
        onEditorBlur(quill) {},
        onEditorFocus(quill) {},
        onEditorReady(quill) {},
        onEditorChange({ quill, html, text }) {
          this.form.content = html
        },
        insertVideo() {
          this.editor.insertEmbed(
            this.editor.selection.savedRange.index,
            'video',
            `${this.$store.state.constant.aliPath}${url}`
          )
        },
        insertImage() {
          this.editor.insertEmbed(
            this.editor.selection.savedRange.index,
            'image',
            `${this.$store.state.constant.aliPath}${url}`
          )
        }
      }
    }
  </script>
</template>
复制代码

vue 封装拖曳和点击上传文件

<template>
  <div class="zy-upload">
    <div
      class="upload-container"
      @drop="drop($event)"
      @dragenter="dragenter($event)"
      @dragover="dragover($event)"
      @click="handlerFileClick"
    >
      <template v-if="progressStatus===1">
        <zy-img src="upload.png" :type="2" class="upload-img"></zy-img>
        <div class="tip">
          点击或将文件拖拽至此区域 支持(xls、xlsx)格式的文件
        </div>
      </template>
      <template v-else-if="progressStatus ===2">
        <zy-circle-progress
          v-if="isShow"
          ref="$circle"
          class="progress upload-img"
          :isAnimation="true"
          :isRound="true"
          :width="width"
          :radius="radius"
          :progress="progress"
          :barColor="barColor"
          :duration="duration"
          :delay="delay"
          :timeFunction="timeFunction"
          :backgroundColor="backgroundColor"
        ></zy-circle-progress>
        <div class="tip">
          点击或将文件拖拽至此区域 支持(xls、xlsx)格式的文件
        </div>
      </template>
      <template v-else>
        <zy-img src="excel.png" :type="2" class="upload-img"></zy-img>
        <div class="tip">
          {{fileName}}
        </div>
      </template>
    </div>
    <input
      @change="handlerUploadFile($event)"
      type="file"
      ref="upload"
      style="display: none"
    />
  </div>
</template>

<script>
  /* eslint-disable*/
  export default {
    data() {
      return {
        fileName: '',
        isShow: true,
        width: 56,
        radius: 3,
        progress: 0,
        duration: 1000,
        delay: 20,
        barColor: '#6BBE4E',
        backgroundColor: '#eee',
        timeFunction: 'cubic-bezier(0.8, 0.01, 0.2, 0.9)',
        progressStatus: 1
      }
    },
    methods: {
      async beforeUpload(content) {
        let params = await this.$store
          .dispatch('getAllOss', 'wind-control-valve/')
          .then(res => {
            return res.data
          })
        params.data.file = content
        let data = await this.$store.dispatch('setParams', params.data)
        let url = params.data.host
        return this.$store.dispatch('upload', { url, data }).then(res => {
          this.progress = res.progress
          this.progressStatus = res.progress < 100 ? 2 : 3
          return res.data
        })
      },
      dragenter(el) {
        el.stopPropagation()
        el.preventDefault()
      },
      dragover(el) {
        el.stopPropagation()
        el.preventDefault()
      },
      drop(el) {
        el.stopPropagation()
        el.preventDefault()
        let dt = el.dataTransfer
        for (let i = 0; i !== dt.files.length; i++) {
          if (
            dt.files[i].type ===
              'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
            dt.files[i].type === 'application/vnd.ms-excel'
          ) {
            this.beforeUpload(dt.files[i]).then(res => {
              console.log('res', res)
            })
            this.fileName = dt.files[i].name
          } else {
            console.warn('文件格式不正确')
          }
        }
      },
      handlerFileClick() {
        this.$refs.upload.click()
      },
      handlerUploadFile(el) {
        if (
          el.target.files[0].type ===
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
          el.target.files[0].type === 'application/vnd.ms-excel'
        ) {
          this.beforeUpload(el.target.files[0]).then(res => {
            console.log('res', res)
          })
          this.fileName = el.target.files[0].name
        } else {
          console.warn('文件格式不正确')
        }
      }
    }
  }
</script>

<style scoped lang="scss">
  .zy-upload {
    width: 392px;
    height: 202px;
    background: rgba(255, 255, 255, 1);
    border-radius: 4px;
    border: 1px dashed rgba(151, 151, 151, 1);
    &:hover {
      cursor: pointer;
    }
    .upload-container {
      width: 100%;
      height: 100%;
    }
    .upload-img {
      margin: 50px 0 0 166px;
    }
    .tip {
      width: 156px;
      height: 32px;
      font-size: 12px;
      text-align: center;
      color: rgba(84, 98, 115, 1);
      line-height: 16px;
      margin: 10px 0 0 118px;
    }
  }
</style>
#axios 进度条值
return new Promise((resolve, reject) => {
  let progress = 0
  http
    .post(url, data, {
      headers: {
        'Content-Type': 'multipart/form-data'
      },
      onUploadProgress: progressEvent => {
        // 使用本地 progress 事件
        if (progressEvent.lengthComputable) {
          progress = Math.round(
            (progressEvent.loaded / progressEvent.total) * 100
          )
        }
      }
    })
    .then(res => {
      res.progress = progress
      resolve(res)
    })
    .catch(err => {
      reject(err)
    })
})
复制代码

vue 结束日期与当前时间倒计时 30m

<template>
  <span v-if="show">{{prifx}}{{time}}</span>
</template>

<script>
  /* eslint-disabled */
  export default {
    data() {
      return {
        time: '',
        flag: false,
        show: false
      }
    },
    mounted() {
      const time = setInterval(() => {
        if (this.flag === true) {
          clearInterval(time)
        }
        this.timeDown()
      }, 1000)
    },
    props: {
      endTime: {
        type: String
      },
      prifx: {
        type: String
      }
    },
    methods: {
      timeDown() {
        if (this.endTime) {
          this.show = true
          const endTime = new Date(this.endTime)
          endTime.setMinutes(endTime.getMinutes() + 30)
          const nowTime = new Date()
          const leftTime = ~~((endTime.getTime() - nowTime.getTime()) / 1000)
          const d = ~~(leftTime / (24 * 60 * 60))
          const h = this.formate(~~((leftTime / (60 * 60)) % 24))
          const m = this.formate(~~((leftTime / 60) % 60))
          const s = this.formate(~~(leftTime % 60))
          if (leftTime <= 0) {
            this.flag = true
            this.show = false
            this.$emit('time-end')
          }
          this.time = `${m}:${s}` // 显示时间格式
        }
      },
      formate(num) {
        if (num >= 10) {
          return num
        }
        return `0${num}`
      }
    }
  }
</script>
复制代码

组件调用

<count end-time="2019-04-24 17:07:00"></count>
复制代码

vue qrcode 生成二维码

<template>
  <div id="qrCode">
    <div id="code"></div>
    <canvas id="canvas"></canvas>
  </div>
</template>
<style></style>
<script>
  import QRCode from 'qrcode'

  export default {
    props: ['url'],
    data() {
      return {
        msg: 'hello vue',
        codes: ''
      }
    },

    components: {
      QRCode
    },

    methods: {
      useqrcode() {
        let canvas = document.getElementById('canvas')
        QRCode.toCanvas(canvas, this.url || window.location.href, error => {
          if (error) console.error(error)
          console.log('QRCode success!')
        })
      }
    },

    mounted() {
      this.useqrcode()
    }
  }
</script>
复制代码

vue 监听滚动条

export default {
  methods: {
    handleScroll() {
      let clientHeight =
        document.documentElement.clientHeight || document.body.clientHeight
      // 设备/屏幕高度
      let scrollObj = document.getElementById(div) // 滚动区域
      // document.documentElement.scrollTop || document.body.scrollTop;
      let scrollTop = scrollObj.scrollTop // div 到头部的距离
      let scrollHeight = scrollObj.scrollHeight // 滚动条的总高度
      //滚动条到底部的条件
      if (scrollTop + clientHeight == scrollHeight) {
        // div 到头部的距离 + 屏幕高度 = 可滚动的总高度
      }
    }
  },
  mounted() {
    window.addEventListener('scroll', this.handleScroll, true)
  }
  destroyed() {
    window.removeEventListener("scroll", this.handleScroll);
  }
}
复制代码

textarea 随文字自适应高度

<textarea
  ref="textarea"
  disabled
  class="proposal"
  v-model="item.proposal"
></textarea>

<script>
  this.$refs.textarea[0].style.minHeight = `${this.$refs.textarea[0].scrollTop +
    this.$refs.textarea[0].scrollHeight}px`
</script>
复制代码

结语

以上就是送给萌新的常见业务需求,修修改改应该就能完成需求了,也但愿萌新们能快速成长!

相关文章
相关标签/搜索