vue一些demo整理

020 vue3.0自定义指令实现一键复制

官方文档链接:自定义指令
created:在绑定元素的 attribute 或事件监听器被应用之前调用。在指令需要附加须要在普通的 v-on 事件监听器前调用的事件监听器时,这很有用。

beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用。

mounted:在绑定元素的父组件被挂载后调用。

beforeUpdate:在更新包含组件的 VNode 之前调用。

提示

我们会在稍后讨论渲染函数时介绍更多 VNodes 的细节。

updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用。

beforeUnmount:在卸载绑定元素的父组件之前调用

unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次。

 app.directive('copy', {
  /*
    一键复制自定义指令
  */
  beforeMount (el: any, binding: any) {
    el.$value = binding.value // 用一个全局属性来存传进来的值,因为这个值在别的钩子函数里还会用到
    el.handler = () => {
      if (!el.$value) {
        // 值为空的时候,给出提示,我这里的提示是用的 ant-design-vue 的提示,你们随意
        console.log('无复制内容')
        return
      }
      // 动态创建 textarea 标签
      const textarea: any = document.createElement('textarea')
      // 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
      textarea.readOnly = 'readonly'
      textarea.style.position = 'absolute'
      textarea.style.left = '-9999px'
      // 将要 copy 的值赋给 textarea 标签的 value 属性
      textarea.value = el.$value
      // 将 textarea 插入到 body 中
      document.body.appendChild(textarea)
      // 选中值并复制
      textarea.select()
      textarea.setSelectionRange(0, textarea.value.length)
      const result = document.execCommand('Copy')
      if (result) {
        ElMessage({
          message: '已复制到粘贴板!',
          type: 'success',
        })
      }
      document.body.removeChild(textarea)
    }
    // 绑定点击事件,就是所谓的一键 copy 啦
    el.addEventListener('click', el.handler)
  },
  // 当传进来的值更新的时候触发
  updated (el: any, binding: any) {
    el.$value = binding.value
  },
  // 指令与元素解绑的时候,移除事件绑定
  unmounted (el: any) {
    el.removeEventListener('click', el.handler)
  },
})

使用:

<button v-copy="要复制的内容">复制</button>

019 h5 draggable属性实现拖拽

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
.list {
  list-style: none;
}
  .drag-move {
    transition: transform .3s;
  }
  .list-item {
    cursor: move;
    width: 300px;
    background: #EA6E59;
    border-radius: 4px;
    color: #FFF;
    margin-bottom: 6px;
    height: 50px;
    line-height: 50px;
    text-align: center;
  }

  </style>
<body>
  <div id="app">
    
    <div>
      <transition-group
        name="drag"
        class="list"
        tag="ul"
      >
        <li
          @dragenter="dragenter($event, index)"
          @dragover="dragover($event, index)"
          @dragstart="dragstart(index)"
          draggable
          v-for="(item, index) in list"
          :key="item.label"
          class="list-item">
          {{item.label}}
        </li>
      </transition-group>
    </div>
  
</div>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.common.dev.js"></script>
<script>
let app = new Vue({
      el:'#app',
      data() {
    return {
      list: [
        { label: '列表1' },
        { label: '列表2' },
        { label: '列表3' },
        { label: '列表4' },
        { label: '列表5' },
        { label: '列表6' },
      ],
      dragIndex: '',
      enterIndex: '',
    };
  },
  methods: {
    shuffle() {
      this.list = this.$shuffle(this.list);
    },
    dragstart(index) {
      this.dragIndex = index;
    },
    dragenter(e, index) {
      e.preventDefault();
      // 避免源对象触发自身的dragenter事件
      if (this.dragIndex !== index) {
        // 避免重复触发目标对象的dragenter事件
        if (this.enterIndex !== index) {
          const moving = this.list[this.dragIndex];
          this.list.splice(this.dragIndex, 1);
          this.list.splice(index, 0, moving);
          // 排序变化后目标对象的索引变成源对象的索引
          this.dragIndex = index;
        } else {
          this.enterIndex = index;
        }
      }
    },
    dragover(e, index) {
      e.preventDefault();
    },
  },
})

</script>
</body>
</html>

018 自定义拖拽指令

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box {
            position: absolute;
            left: 100px;
            top: 100px;
            width: 100px;
            height: 100px;
            background: red;
        }
    </style>
</head>
<body>

    <div id="app">
        <button @click="canDrag = !canDrag">Drag : {{canDrag}}</button>
        <div class="box" v-drag.limit="canDrag"></div>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>

        Vue.directive('drag', {
            bind(el, {modifiers,value}) {
                let isDragStart = false;
                let disX = 0;
                let disY = 0;
                el.canDrag = value;
                el.addEventListener('mousedown', e => {
                    if (!el.canDrag) return;
                    disX = e.clientX - el.offsetLeft;
                    disY = e.clientY - el.offsetTop;
                    isDragStart = true;

                    e.preventDefault();
                });
                document.addEventListener('mousemove', e => {
                    if (isDragStart) {
                        let x = e.clientX - disX;
                        let y = e.clientY - disY;

                        if (modifiers.limit) {
                            if (x < 0) {
                                x = 0;
                            }
                            if (y < 0) {
                                y = 0;
                            }
                        }

                        el.style.left = x + 'px';
                        el.style.top = y + 'px';
                    }
                });
                document.addEventListener('mouseup', e => {
                    isDragStart = false;
                });
            },
            componentUpdated(el, {value}) {
                console.log('componentUpdated', value);
                el.canDrag = value;
            }
        });
        
        let app = new Vue({
            el: '#app',
            data: {
                canDrag: false
            }
        });
    </script>
</body>
</html>

017 uniapp微信小程序中自定义轮播图小圆点

<template>
  <view class="banner">
    <swiper
      class="swiper"
      circular
      :autoplay="autoplay"
      :interval="interval"
      :duration="duration"
      @change = "bannerFun"
    >
      <swiper-item
        v-for="(item,index) in swiperList"
        :key="index"
        :data-type="item.routeType"
        @click="goTonNvigate(item.bizJson, item.routeType, item.bizId)" >
        <view class="swiper-item">
          <image class="swiper-item__img" :src="item.imageUrl"></image>
        </view>
      </swiper-item>
    </swiper>
    <!-- 自定义轮播图指示点 -->
    <view class="instructWrap">
      <block v-for="(item,index) in instructdata" :key="index">
        <view
          class="instruct"
          :class="{active:index === current}"
        >
          {{item}}
        </view>
      </block>
    </view>
  </view>
</template>
<script>
export default {
  name: 'swiperList',
  props: ['swiperList'],

  data() {
    return {
      autoplay: true,
      duration: 1000,
      interval: 3000,
      current: 0,
      instructdata: [''], // 面板指示点
    };
  },
  created() {
    while (this.instructdata.length < this.swiperList.length) {
      this.instructdata.push('');
    }
  },
  computed: {},
  methods: {
    goTonNvigate(bizJson, routeType, bizId) {
      this.$emit('goTonNvigate', bizJson, routeType, bizId);
    },
    // 圆点事件
    bannerFun(e) {
      this.current = e.detail.current;
    },
  },
};
</script>
<style lang='scss' scoped>
.banner {
  width: 750rpx;
  position: relative;
  .swiper {
    width: 702rpx;
    height: 290rpx;
    background-color: #ffffff;
    margin: 0 auto;
    border-radius: 8rpx;
    overflow: hidden;
    swiper-item {
      overflow: hidden;
      border-radius: 8rpx;
    }
    .swiper-item,
    .swiper-item__img {
      height: 100%;
      width: 100%;
      border-radius: 8rpx;
    }
  }
}

.instructWrap {
  display: flex;
  justify-content: center;
  position: absolute;
  bottom:20rpx;
  left: 50%;
  transform: translate(-50%,-50%);
  // margin-left: -55rpx;
}
.instruct {
  border-radius: 50%;
  margin: 0 10rpx;
  width:8rpx;
  height:8rpx;
  background:rgba(0,0,0,0.7);
  opacity:0.2;
}
.active {
  width:20rpx;
  height:8rpx;
  background:rgba(0,0,0,1) !important;
  border-radius:4rpx;
  opacity:0.4;
}
</style>

016 二级分类选择

在这里插入图片描述
在这里插入图片描述
由于是弹窗形式的:
所有弹窗用了vant的van-action-sheet组件

 <van-action-sheet
        v-model="showOffice"
        title="选择科室"
        >
        <div class="content_office">
          <div class="content_left">
            <ul>
              <li
               :class="[{ content_left_active: activeIndex == index }, content_left_li ]"
               v-for="(item,index) in filterOfficeList" :key="index"
               @click="officeLeft(item,index)">

               {{item.depName}}</li>
            </ul>
          </div>
          <div class="content_Right">
            <ul>
              <li class="content_Right_li" v-for="(child,index) in filterOfficeList[childIdx]?filterOfficeList[childIdx].interDepDTOList:''" :key="index" @click="officeRight(child,index)">{{child.depName}}</li>

            </ul>
          </div>
        </div>
      </van-action-sheet>
.content_office {
    background: #F2F2F2;
   .content_left {
    height:calc(100vh - 130px);
    float: left;
    width:101px;
    background: #F2F2F2;
    ul {
      height 100%;
      overflow-y:auto;
      -webkit-overflow-scrolling: touch;
    }
    // 解决滚动条不消失问题
   ul::-webkit-scrollbar{
      display: none;
   }
    .content_left_li {
      height:48px
      font-size:14px;
      font-weight:500;
      color:rgba(51,51,51,1);
      line-height:48px;
    }
   }
   .content_Right {
    height:calc(100vh - 145px);
    width: calc(100vw - 125px);
    float: left;
    background:#fff;
    margin-left 24px
    margin-top 15px
    ul {
      height 100%;
      overflow-y:auto;
      -webkit-overflow-scrolling: touch;
    }
    // 解决滚动条不消失问题
   ul::-webkit-scrollbar{
      display: none;
   }
    .content_Right_li {
      height 20px
      margin-bottom 28px
      text-align left
    }

015 vue 三秒倒计时跳转页面

在这里插入图片描述

<template>
  <div style="width: 100%;height: 100%;background:#fff;">
    <div id="successInquiry_title" :style="{'background':'#fff'}">
      <span class="successInquiry_back" @click="$router.go(-1)">
        <van-icon name="arrow-left" />
      </span>
      <span class="successInquiry_label">预约确认</span>
    </div>
    <div class="pays_content">
      <div class="pays_imgCon">
        <img src="../assets/images/Payment_success_icon@2x.png" />
      </div>
      <div class="pays_titleCon">支付成功</div>
      <div class="pays_operationPart">
        <span>{{count}}s</span>后自动跳转至问诊会话页
      </div>
    </div>
  </div>
</template>
<script type="text/javascript">
export default {
  data() {
    return {
      // 存储支付成功后订单数据
      inquirIrderInfo: JSON.parse(sessionStorage.inquirypayData),
      count: '', // 倒计时
    };
  },
  components: {},
  methods: {
    // 进入im
    goIM() {
      this.$router.push({
        name: 'im',
        query: {
          orderId: this.inquirIrderInfo.medRdNo,
        },
      });
    },
    goInquirDetail() {
      this.$router.replace({
        name: 'inquirDetail',
        query: { inquirId: this.inquirIrderInfo.medRdNo },
      });
    },
  },
  created() {},
  mounted() {
    const TIME_COUNT = 3;
    if (!this.timer) {
      this.count = TIME_COUNT;
      this.timer = setInterval(() => {
        if (this.count > 1 && this.count <= TIME_COUNT) {
          this.count -= 1;
        } else {
          clearInterval(this.timer);
          this.timer = null;
          this.$router.push({
            name: 'im',
            query: {
              orderId: this.inquirIrderInfo.medRdNo,
            },
          });
        }
      }, 1000);
    }
  },
  beforeDestroy() {
    clearInterval(this.timer);
  },
};
</script>
<style type="text/css" lang="scss" scoped>
@import '../assets/css/_common.scss';
#successInquiry_title {
  width: 100%;
  height: 44px;
  line-height: 44px;
  text-align: center;
  z-index: 100;
  display: -webkit-flex;
  display: flex;
  -webkit-align-items: center;
  align-items: center;
  -webkit-justify-content: center;
}

.successInquiry_back {
  position: absolute;
  left: 10px;
  font-size: 21px;
  display: -webkit-flex;
  display: flex;
  -webkit-align-items: center;
  align-items: center;
  -webkit-justify-content: center;
  color: #383838;
}

.successInquiry_label {
  width: 72px;
  height: 18px;
  font-size: 18px;
  font-weight: 500;
  color: rgba(73, 72, 71, 1);
  line-height: 18px;
}
.pays_content {
  width: 100%;
  height: 100%;
  position: fixed;
  background: #fff;
  font-size: 14px;
}

.pays_imgCon {
  margin-top: 68px;
  text-align: center;

  img {
    width: 70px;
    height: 70px;
  }
}

.pays_titleCon {
  width: 100%;
  text-align: center;
  margin-top: 16px;
  font-size: 24px;
  font-family: PingFangSC-Medium, PingFangSC;
  font-weight: 500;
  color: rgba(73, 72, 71, 1);
  line-height: 22px;
}

.pays_operationPart {
  width: 100%;
  text-align: center;
  margin-top: 8px;
  font-size: 12px;
  font-family: PingFangSC-Regular, PingFang SC;
  font-weight: 400;
  line-height: 17px;
  span {
    color: rgba(0, 122, 255, 1);
  }
}

.pays_operation1 {
  width: 120px;
  height: 40px;
  line-height: 40px;
  // background: $theme_color;
  color: rgba(42, 213, 213, 1);
  border-radius: 24px;
  border: 1px solid rgba(42, 213, 213, 1);
}

.pays_operation2 {
  width: 120px;
  height: 40px;
  line-height: 40px;
  background: rgba(42, 213, 213, 1);
  color: #fff;
  border-radius: 4px;
  box-sizing: border-box;
  border-radius: 24px;
  border: 1px solid rgba(42, 213, 213, 1);
  margin-left: 15px;
}
</style>

014 vue真机调试vsconsole

在这里插入图片描述
1、npm install vconsole
2、在main.js文件中

import Vconsole from 'vconsole';
const vConsole = new Vconsole();
// Vue.use(vConsole)

013 VUE 实现一键复制文字到粘贴板

在这里插入图片描述

<h2>{{text}}</h2><button @click="toCopy(text)">复制到粘贴板</button>
data() {
    return {
      text:'TJA145452147854785477'
    }
  },
  methods: {
    toCopy(toBeCopy){
      console.log(toBeCopy)
      var tag = document.createElement('input');
      tag.setAttribute('id', 'cp_hgz_input');
      tag.value = toBeCopy;
      document.getElementsByTagName('body')[0].appendChild(tag);
      document.getElementById('cp_hgz_input').select();
      document.execCommand('copy');
      document.getElementById('cp_hgz_input').remove();
      alert("复制成功!");
    },
  }

012 VUE 实现无痕刷新页面

在这里插入图片描述
在不刷新浏览器的情况下,实现页面的刷新。

传统的刷新页面方式

window.location.reload()原生 js 提供的方法

this.$router.go(0)vue 路由里面的一种方法

这两种方法都可以达到页面刷新的目的,简单粗暴,但是用户体验不好,相当于按 F5 刷新页面,页面的重新载入,会有短暂的白屏
1.先在全局组件注册一个方法,用该方法控制 router-view 的显示与否,然后在子组件调用;

用 v-if 控制 的显示;

provide:全局注册方法;

inject:子组件引用 provide 注册的方法

<template>
  <div id="app">
    <router-view v-if="isShow"></router-view>
  </div>
</template>
<script>
export default {
   provide(){
    return{
      reload:this.pageReload
    }
  },
   data(){
    return{
      isShow:true
    }
  },
   methods:{
   //刷新
    pageReload(){
      this.isShow=false;
      this.$nextTick(()=>{
        this.isShow=true;
      })
    }
  },
  created() {
    console.log(process.env,'APP');
  }
}
</script>

需要进行无痕刷新的页面使用方法

<template>
   <div>
       <button@click="handleReload()">点击刷新</button>
   </div>
</template>

<script>
exportdefault{
   name:"Home",
   inject:["reload"],
   methods:{
       handleReload(){
           this.reload()
      }
  },
   created(){
       console.log(111)
  }
}
</script>

011 时间戳转正常日期

法1.

function dateFormat(time, format = "YYYY-MM-DD HH:mm:ss") {
  let date = new Date(time)
  const config = {
    YYYY: date.getFullYear(),
    MM: date.getMonth() + 1,
    DD: date.getDate(),
    HH: date.getHours(),
    mm: date.getMinutes(),
    ss: date.getSeconds()
  };
  for (const key in config) {
    format = format.replace(key, config[key]);
  }
  return format;
}
console.log(dateFormat(1588754368262, "YYYY年MM月DD日"));

方法2.用作过滤器
在这里插入图片描述
在这里插入图片描述

export const dateFormat = (ms) => {
  let date = new Date(ms)
  let y = String(date.getFullYear()).padStart(4, 0)
  let M = String(date.getMonth() + 1).padStart(2, 0)
  let d = String(date.getDate()).padStart(2, 0)
  let h = String(date.getHours()).padStart(2, 0)
  let m = String(date.getMinutes()).padStart(2, 0)
  let s = String(date.getSeconds()).padStart(2, 0)
  return `${y}-${M}-${d} ${h}:${m}:${s}`
}

010 vue自定义倒计时组件

在这里插入图片描述

<template>
 <div>
    <!-- <span v-show="!isShow"> -->
    <span>
      <span class="hour" v-text="hh"></span>
      <span class="minute" v-text="mm"></span>
      <span class="second" v-text="ss"></span>
  </span>
    <!-- 这里是显示结束后的内容 -->
    <!-- <span class="second" v-show="isShow">{{endMsg}}</span> -->
 </div>
</template>
<script>
export default {
  name: 'downTime',
  props: {
  // 接收一个秒数
    second: {
      type: [String, Number],
    },
    endMsg: {
      type: String
    }
  },
  data () {
    return {
      hh: '00',
      mm: '00',
      ss: '00',
      isShow: false, // 控制显示结束或还未结束显示的内容
      clocker: '', // 结束后显示的内容
    }
  },
  created() {
    this.timer= null
  },
   mounted () {
    let timeLag = parseInt(this.second) //父组件传过来的剩余总秒数
    let timeFunction = () => {
      let time = timeLag--
      // 计算出 时分秒
      this.hh = String(Math.floor(time / 60 / 60) % 24).padStart(2,0) //时
      this.mm = String(Math.floor(time / 60) % 60).padStart(2,0) //分
      this.ss = String(Math.floor(time % 60)).padStart(2,0) //秒
      // 当时间差小于等于0时,停止倒计时
      if (time <= 0) {
        this.$emit('timeEnd')
        this.isShow = true
        this.clocker = this.endMsg || '该团已经结束'
        clearInterval(this.timer)
      }
    }
    // 开始执行倒计时
    timeFunction()
    this.timer = setInterval(() => {
      timeFunction()
    }, 1000)
  },
  beforeDestroy () {
    clearInterval(this.timer)
  }
}
</script>

父组件调用:

<template>
  <div>
    <h2>自定义倒计时组件</h2>
    <down-time :second="second" @timeEnd="timeEnd()" class="tm"></down-time>
  </div>
</template>

<script>
import DownTime from '../components/DownTime'
export default {
  components: { DownTime },
  data() {
    return {
      second: 5
    }
  },
  created() {},
  methods: {
    timeEnd() {
      console.log('接下来做点什么')
    }
  }
}
</script>
<style lang='scss' scoped>
.tm {
  width: 200px;
  height: 20px;
  border: 1px solid #c33;
}
/deep/ .hour {
  &::before {
    content: '剩余';
  }
}
/deep/ .hour {
  &::after {
    content: '时';
  }
}
/deep/ .minute {
  &::after {
    content: '分';
  }
}
/deep/ .second {
  &::after {
    content: '秒';
  }
}
</style>

009 vant实现上拉刷新下拉加载

vue 使用vant ui ui 实现上拉刷新下拉加载

<template>
  <div class="activity-container">
    <HeaderBar title="我的活动" :fixed="true" bgc="#fff"></HeaderBar>
    <van-pull-refresh
      v-model="isLoading"
      @refresh="onRefresh"
      success-text="刷新成功"
      v-if="activityList.length>0">
      <van-list
        v-model="loading"
        :finished="finished"
        :offset="offset"
        finished-text="-没有更多了-"
        @load="onLoad">
        <ul class="activity-wrapper">
          <li class="activity-list" v-for="(item,index) in activityList" :key="index" @click="gotoDetail(item.aId)">
            <div class="activity-list-top">
              <p>{{item.activityName}}</p>
              <span>{{item.activityStatusName}}</span>
            </div>
            <div class="line"></div>
            <div class="activity-describe">
              <p>
                <span class="activity-dress">活动时间:</span>
                <span>{{item.beginTime}}</span>
              </p>
              <p v-show="item.orgAddress">
                <span class="activity-dress">活动地点:</span>
                <span>{{item.orgAddress}}</span>
              </p>
            </div>
          </li>
        </ul>
      </van-list>
    </van-pull-refresh>
    <div class="empty" v-else-if="complete">
      <img :src="emptyImg" alt="">
      <p>抱歉该地区暂无活动动态</p>
    </div>
  </div>
</template>
<script>
import { getActiveList } from '@api/activityList'
export default {
  name: 'MyActivityList',
  data () {
    return {
      complete: false, // 第一次数据请求完成后在来判断是否为空
      isLoading: false, // 下拉刷新
      activityList: [], // 请求数据
      pageSize: 10, // 每页条数
      currentPage: 1, // 页码
      loading: false, // 上拉加载
      finished: false, // 上拉加载完毕
      offset: 100, // 滚动条与底部距离小于 offset 时触发load事件
      emptyImg: require('@/assets/images/activity/pic_empty_activity@2x.png')
    }
  },
  created () {
    this.getActiveList()
  },
  methods: {
    async getActiveList () {
      let res = await getActiveList(this.currentPage)
      let list = res.results[0].pageRecord
      this.activityList = this.activityList.concat(list)
      this.loading = false
      this.complete = true
      if (list == null || list.length === 0) {
        this.finished = true
      }
      if (list.length < this.pageSize) {
        this.finished = true
      }
    },
    // 下拉刷新
    onRefresh () {
      this.complete = false
      this.currentPage = 1
      this.isLoading = false
      this.finished = false
      this.activityList = []
      this.getActiveList() // 加载数据
    },
    // 上拉加载
    onLoad () {
      this.currentPage++
      this.getActiveList()
    },
    gotoDetail(detailId) {
      this.$router.push(`/myActivityDetail/${detailId}`)
    }
  }
}
</script>
<style lang="scss" scoped>
.activity-container {
  padding-top: 0.44rem;
  background-color: #f5f5f5;
}
.activity-wrapper {
  background-color: #fafafa;
  .activity-list {
    padding-left: .2rem;
    margin-bottom: .1rem;
    background-color: #fff;

    .activity-list-top {
      height: .48rem;
      display: flex;
      flex-direction: row;
      padding: 0 .16rem 0 0;
      justify-content: space-between;
      align-items:center;
      & p:nth-of-type(1) {
        max-width: 2.39rem;
        color: #333;
        font-size: .14rem;
        font-weight: 700;
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
      }
      & span:nth-of-type(1) {
        color: #ea5504;
        font-size: .14rem;
      }
    }
    .line {
      border-top-width: 1px;
      border-top-style: solid;
      margin: 0;
      border-top-color: #eee;
    }
    .activity-describe {
      padding: .08rem .08rem .08rem 0;
      color: grey;
      font-size: .14rem;
      .activity-dress {
        display: inline-block;
        width: .7rem;
        margin-right: .29rem;
      }
    }
  }
}
.empty {
  height: 2.91rem;
  background-color: #fff;
  padding-top: 1.5rem;
  img {
    display: block;
    width: 1.2rem;
    height: 1.2rem;
    margin:0 auto;
  }
  & p:nth-of-type(1) {
    text-align: center;
    color: grey;
    font-size: .15rem;
  }
}
</style>

008 Vue简单实现全选全不选按钮

在这里插入图片描述

<template>
  <div id="app">
    <div>
      <input type="checkbox" @click="checkAll" v-model="checked" />
      <span>全选</span>
    </div>
    <ul>
      <li v-for="(item,index) in list" :key="index">
        <input type="checkbox" v-model="checkModel" :value="item.id" />
        <div>名称:{{item.name}}</div>
        <div>价格:{{item.price}}</div>
        <div>产地:{{item.adress}}</div>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: 'About',
  data () {
    return {
      list: [
        { id: 1, name: "苹果", price: 23, adress:'北京' },
        { id: 2, name: "香蕉", price: 18, adress: '上海' },
        { id: 3, name: "鸭梨", price: 29, adress: '山东' }
      ],
      checked: false, //是否全选
      checkModel: [] //双向数据绑定的数组,用的id
    }
  },
  watch: { // 监视双向绑定的数据数组
    checkModel () {
      if (this.checkModel.length == this.list.length) {
        this.checked = true;
      } else {
        this.checked = false;
      }
    }
  },

  methods: {
    checkAll () {
      if (this.checked) {
        this.checkModel = [];
      } else {
        this.list.forEach((item) => {
          if (this.checkModel.indexOf(item.id) == -1) {
            this.checkModel.push(item.id)
          }
        })
      }
    }
  }
}
</script>

带label标签的
在这里插入图片描述

   <ul>
      <li v-for="(item,index) in list" :key="index">
        <label :for="item.id">{{item.name}}</label>
        <input type="checkbox" v-model="checkModel" :value="item.value" :id="item.id"/>
      </li>
    </ul>
    <button @click="test"> 提交</button>
  </div>
</template>
<script>

export default {
  data() {
    return {
      checkModel: [],
      list: [
        { value: '支付宝', name: '支付宝', id: 1 },
        { value: '微信', name: '微信', id: 2 },
        { value: '云闪付', name: '云闪付', id: 3 },
      ],
    };
  },
  methods: {
    test() {
      console.log(this.checkModel);
    },
  },

007vue-简单实现单选按钮

在这里插入图片描述
html:

<p v-for="(item,index) in alpha " :key="index">
      <input type="radio" id="one" :value="item.value" v-model="picked" />
      <label for="item.text">{{item.text}}</label>
      <br />
    </p>
    <span>Picked: {{ picked }}</span>
    <br/>
    <el-button type="success" @click="submit(picked)">提交</el-button>

js:

 data () {
    return {
      picked: 'A',
      alpha: [
        { text: 'A', value: 'A' },
        { text: 'B', value: 'B' },
        { text: 'C', value: 'C' },
        { text: 'D', value: 'D' },
      ],
    }
  }

006 vue后台管理系统表格elementui

在这里插入图片描述
在这里插入图片描述

<template>
  <div class="drugStorageWrap">
    <!-- 搜索條件 -->
    <el-card>
      <el-form ref="searchForm" :inline="true" :model="searchForm" label-width="130px">
        <div>
          <el-form-item label="药品ID:">
            <el-input v-model.trim="searchForm.drugId" placeholder="请选择" clearable></el-input>
          </el-form-item>
          <el-form-item label="商品编码:">
            <el-input v-model.trim="searchForm.productCode" placeholder="请选择" clearable></el-input>
          </el-form-item>
          <el-form-item label="商品名称:">
            <el-input v-model.trim="searchForm.productName" placeholder="请选择" clearable></el-input>
          </el-form-item>
        </div>
        <div>
          <el-form-item label="状态:">
            <el-select clearable v-model.trim="searchForm.status" placeholder="请选择">
              <el-option label="区域一" value="shanghai"></el-option>
              <el-option label="区域二" value="shanghai"></el-option>
              <el-option label="区域三" value="shan"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="供货商:">
            <el-select clearable v-model.trim="searchForm.supply" placeholder="请选择">
              <el-option label="淘寶" value="ttt"></el-option>
              <el-option label="阿里" value="阿里"></el-option>
            </el-select>
          </el-form-item>
          <div class="submit">
            <el-form-item>
              <el-button type="primary" @click="onSubmit">查询</el-button>
            </el-form-item>
          </div>
        </div>
      </el-form>
    </el-card>
    <!-- 列表部分 -->
    <el-table
      :data="tableData"
      border
      stripe
      highlight-current-row
      :header-cell-style="{background:'#eef1f6',color:'#606266'}"
      style="width: 100%"
      class="table"
    >
      <el-table-column prop="date" label="药品ID" header-align="center"></el-table-column>
      <el-table-column prop="name" label="药品编码" header-align="center"></el-table-column>
      <el-table-column prop="province" label="药品名称" header-align="center"></el-table-column>
      <el-table-column prop="city" label="规格" header-align="center"></el-table-column>
      <el-table-column prop="address" label="生产厂家" header-align="center"></el-table-column>
      <el-table-column prop="zip" label="供货商" header-align="center"></el-table-column>
      <el-table-column prop="zip" label="成本" header-align="center"></el-table-column>
      <el-table-column prop="zip" label="售价" header-align="center"></el-table-column>
      <el-table-column prop="zip" label="库存" header-align="center"></el-table-column>
      <el-table-column label="上架" width="150" header-align="center">
        <template slot-scope="scope">
          <!-- <el-button @click="handleClick(scope.row)" type="text" size="small">上架</el-button> -->
          <el-switch
            v-model="scope.row.msg_status"
            active-color="#13ce66"
            inactive-color="#ff4949"
            @change="changeUpDrug(scope.row)"
          ></el-switch>
        </template>
      </el-table-column>
      <el-table-column label="操作" width="150" header-align="center">
        <template slot-scope="scope">
          <el-button @click="edit(scope.row)" type="text" size="small">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 翻頁 -->
    <div class="paginationWrap">
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page.sync="searchForm.pageNum"
        :page-size="searchForm.pageSize"
        layout="total, prev, pager, next"
        :total="tatal"
      ></el-pagination>
    </div>
    <!-- dialog -->
    <div class="editDialog">
      <el-dialog title="编辑" :visible.sync="dialogFormVisible" width="490px" @close="resetForm">
        <el-form :model="editForm" ref="editFormRef">
          <el-form-item label="药品ID:" :label-width="formLabelWidth">
            <el-input v-model="editForm.name" autocomplete="off" :disabled="true"></el-input>
          </el-form-item>
          <el-form-item label="商品编码:" :label-width="formLabelWidth">
            <el-input v-model="editForm.id" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item label="成本:" :label-width="formLabelWidth">
            <el-input v-model="editForm.name" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item label="售价:" :label-width="formLabelWidth">
            <el-input v-model="editForm.name" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item label="库存:" :label-width="formLabelWidth">
            <el-input v-model="editForm.name" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item label="供货商:" :label-width="formLabelWidth">
            <el-select v-model="editForm.addres" placeholder="请选择">
              <el-option label="区一" value="shanghai"></el-option>
              <el-option label="区二" value="beijing"></el-option>
            </el-select>
          </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer" style="text-align: center;">
          <el-button type="primary" @click="dialogFormVisible = false">保存</el-button>
        </div>
      </el-dialog>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      searchForm: {
        drugId: '', //药品ID
        productCode: '', //商品编码
        productName: '', //商品名称
        status: '', //状态
        supply: '', //供货商
        pageNum: 1,
        pageSize: 10
      },
      dialogFormVisible: false, // 彈窗
      editForm: {
        name: '',
        addres: ''
      },
      formLabelWidth: '120px',
      tatal: 100,
      tableData: [
        {
          date: '2016-05-02',
          name: '王小虎',
          province: '上海',
          city: '普陀区',
          address: '上海市普 1518 弄',
          id: 1001,
          msg_status: true
        },
        {
          date: '2016-05-04',
          name: '王小虎',
          province: '上海',
          city: '普陀区',
          address: '上海市普陀区 1517 弄',
          id: 1002,
          msg_status: false
        },
        {
          date: '2016-05-01',
          name: '王小虎',
          province: '上海',
          city: '普陀区',
          address: '上海市普陀区 1519 弄',
          id: 1003,
          msg_status: false
        },
        {
          date: '2016-05-03',
          name: '王小虎',
          province: '上海',
          city: '普陀区',
          address: '上海市普陀区 1516 弄',
          id: 1004,
          msg_status: true
        }
      ]
    }
  },
  methods: {
    //提交 搜索
    onSubmit() {
      console.log('submit!')
      console.log(this.searchForm)
    },
    //編輯彈窗
    edit(row) {
      // console.log(row)
      this.editForm.name = row.id
      this.dialogFormVisible = true
    },
    //上下架狀態
    changeUpDrug(info) {
      console.log(info)
    },
    //重置表單
    resetForm() {
      this.$refs.editFormRef.resetFields()
    },
    handleSizeChange(newSize) {
      this.searchForm.pageSize = newSize
      console.log(`每页 ${newSize}`)
    },
    handleCurrentChange(newPage) {
      this.searchForm.pageNum = newPage
      console.log(`当前页: ${newPage}`)
    }
  }
}
</script>
<style lang="scss" scoped>
.el-form {
  padding: 30px;
}
.drugStorageWrap /deep/ .el-form-item__content {
  width: 197px !important;
}
.submit {
  display: inline-block;
  margin-left: 257px;
}
/deep/.el-table th > .cell {
  text-align: center;
}
/deep/.el-table .cell {
  text-align: center;
}
.editDialog /deep/ .el-dialog__header {
  border-bottom: 1px solid #ccc;
}
.table {
  margin-bottom: 15px;
}
.paginationWrap {
  position: relative;
  .el-pagination {
    position: absolute;
    right: 0;
  }
}
</style>

005短信验证码60倒计时

export default {
  data () {
    return {
      btnColor: '#ea5504',
      content: '发送验证码', // 按钮里显示的内容
      totalTime: 90, // 记录具体倒计时间 s
      typeBtn: 'warning',
      sendBtnDisabled: false, // 发送短信按钮状态
      captchaId: '', // 图形验证码验证id
      verifyFlag: false,
      imgCode: '',
      active: 0,
      activeType: '',
      formData: {
        userName: '',
        telephone: '',
        SMSVerCode: '',
        VerifyCode: ''
      },
      nameType: false,
      phoneType: false,
      phoneLicit: false,
      codeType: false,
      codeVerifyType: false
    }
  },
  directives: {
    fours: {
      inserted (el, bindings, vnode) { // 指令元素插入到页面时执行
        el.changeValue = function (e) {
          if (el.value.trim()) {
            switch (bindings.value) {
              case 'name':
                vnode.context['nameType'] = false
                break
              case 'phone':
                vnode.context['phoneType'] = false
                vnode.context['phoneLicit'] = !/^1\d{10}$/.test(el.value.trim())
                break
              case 'code' :
                vnode.context['codeType'] = false
                break
              case 'codeVerify' :
                vnode.context['codeVerifyType'] = false
                break
            }
          } else {
            vnode.context[`${bindings.value}Type`] = true
          }
        }
        el.onblur = function () {
          el.changeValue()
        }
        el.onfocus = function () {
          // 对比名称一样加边框颜色
          vnode.context['activeType'] = bindings.value
        }
        el.oninput = el.changeValue
      }
    }
  },
  methods: {
    // 计算class类名
    classObject (value) {
      return {
        active: this.activeType === value,
        bdColor: value === 'phone' && (this.phoneLicit || this[`${value}Type`])
      }
    },
    // 清除数据
    reset (value) {
      this.formData[value] = ''
    },
    // 发送验证码
    async sendCode () {
      let res = await getReportCode({
        captchaId: this.captchaId,
        captchaValue: this.formData.VerifyCode,
        clientId: 'h5',
        clientName: 'h5_mobile',
        mobile: this.formData.telephone
      })
      if (res.code === '30000') {
        this.verifyFlag = true
        this.createVerifyVode()
      }
      if (res.code === '30001') {
        this.$notify({
          message: res.message,
          color: '#ff9f0a',
          background: '#fff8ea'
        })
        this.createVerifyVode()
      }
      if (res.code === 1) {
        this.sendBtnDisabled = true
        this.typeBtn = 'info'
        this.btnColor = '#d9d9d9'
        this.content = this.totalTime + 's后重新获取'
        let timer = setInterval(() => {
          this.totalTime--
          this.content = this.totalTime + 's后重新获取'
          if (this.totalTime < 0) {
            clearInterval(timer)
            this.content = '发送验证码'
            this.totalTime = 90
            this.sendBtnDisabled = false
            this.typeBtn = 'warning'
            this.btnColor = '#ea5504'
          }
        }, 1000)
      }

004 element ui 中 el-upload 组件 用自定义函数覆盖

效果图
在这里插入图片描述
在这里插入图片描述

<div class="formWrap" v-show="showImg == 1">
        <el-form-item label="图片地址:" :label-width="labelWidth">
          <el-upload
            action="#"
            :http-request="uploadImg"    //uploadImg    自定义请求函数
            :on-remove="handleRemove"     //图片移除
            :on-preview="handlePreview"  //图片预览
            :limit="1"
            list-type="picture"
            :file-list="fileList"
          >
            <el-button size="small" type="primary">点击上传</el-button>
          </el-upload>
        </el-form-item>
      </div>

在这里插入图片描述

methods: {
    async uploadImg(param) {
      const value = param.file
      let formData = new FormData()
      formData.append('file', value)
      const res = await uploadFile(formData)
      if (res.code === 1) {
        this.fileId = res.fileId
        //获取图片路径地址接口
        this.getImgUrl()
      } else {
        this.$message({
          type: 'error',
          message: res.message
        })
      }
    },
    handlePreview(file){},
    // 图片移除
    handleRemove(file) {
      const filePath = file.url
      const i = this.fileList.findIndex(item => item.url === filePath)
      this.fileList.splice(i,1)
    }
 }

003 简单版购物车

在这里插入图片描述
代码示例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <div v-for="(item,index) in goods">
            <div>{{item.goodsName}}</div>
            <div>单价:{{item.price}}</div>
            <button @click="handleReduce(index)">-</button>
            <input type="text" v-model="item.n">
            <button @click="handleAdd(index)">+</button>
        </div>
        <h2>已选则{{total.countNum}}件商品,总价:{{total.countPrice}}</h2>
    </div>
</body>

</html>
<script src="vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            goods: [{
                goodsName: "三只松鼠",
                n: 1,
                price: 99.9
            }, {
                goodsName: "三只蝙蝠",
                n: 1,
                price: 77
            }, {
                goodsName: "iphone20",
                n: 1,
                price: 99
            }]
        },
        methods: {
            handleReduce(index) {
                if (this.goods[index].n <= 1) {
                    this.goods[index].n = 1
                } else {
                    this.goods[index].n--
                }
            },
            handleAdd(index) {
                this.goods[index].n++;
            }
        },
        computed: {
            total() {
                var countNum = 0,
                    countPrice = 0;
                for (var i = 0; i < this.goods.length; i++) {
                    countNum += this.goods[i].n;
                    countPrice += (this.goods[i].n * (this.goods[i].price * 100)) / 100;
                }

                return {
                    countNum,
                    countPrice
                }
            }
        }
    })
</script>

002 tab切换

在这里插入图片描述
代码示例

<template>
  <div>
    <ul>
      <li
        :class="currentIndex == index ? 'active' : ''"
        v-for="(item, index) in list"
        :key="item.id"
        @click="toggle(index)"
      >
        {{ item.title }}
      </li>
    </ul>
    <div
      v-for="(item, index) in list"
      v-show="currentIndex == index"
      :key="item.id"
    >
      <p>{{ item.content }}</p>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      currentIndex: 0, // 选项卡当前的索引
      list: [
        {
          id: 1,
          title: "apple",
          content: "我是一个苹果"
        },
        {
          id: 2,
          title: "orange",
          content: "我是一个橙子"
        },
        {
          id: 3,
          title: "lemon",
          content: "我是一个柠檬"
        }
      ]
    };
  },
  methods: {
    toggle(index) {
      // 在这里实现选项卡切换操作:本质就是操作类名
      // 如何操作类名?就是通过currentIndex
      this.currentIndex = index;
    }
  }
};
</script>
<style>
* {
  padding: 0;
  margin: 0;
}
ul {
  overflow: hidden;
}
ul li {
  box-sizing: border-box;
  padding: 0;
  float: left;
  width: 100px;
  height: 45px;
  line-height: 45px;
  list-style: none;
  text-align: center;
  cursor: pointer;
}
.active {
    border-bottom: 1px solid pink;
}
.current {
  width: 300px;
  height: 300px;
  text-align: center;
  font-size: 30px;
  line-height: 300px;
  border: 1px solid red;
}
</style>

001 todolist简陋版

在这里插入图片描述
代码示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <input type="text" v-model="msg">
        <button @click="handleAdd">添加</button>
        <ul>
            <li v-for="(item,index) in list">{{item}}
                <button @click="handleDel(index)">删除</button>
            </li>
        </ul>
    </div>
</body>
</html>
<script src="vue.js"></script>
<script>
    let vm = new Vue({
        el:"#app",
        data:{
            msg:"",
            list:[]
        },
        methods:{
            handleAdd(){
               this.list.push(this.msg);
               this.msg = ""; 
            },
            handleDel(index){
                this.list.splice(index,1)
            }
        }
    })
</script>
  • 5
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue详情页demo可以用来展示一些特定的产品或者内容的详细信息。这个demo包含了一个列表页面和一个详情页面,用户可以通过点击列表页面中的某一项来查看详情页面。 首先,在列表页面中,我们可以使用Vue提供的v-for指令来遍历一个包含多个项的数组。每个项可以包含产品的名称、图片、简介等信息。当用户点击某一项时,可以通过v-bind将该项的信息传递给详情页面。 然后,在详情页面中,我们可以接收传递过来的信息,并展示在页面上。可以通过使用插值语法来动态显示产品的名称、图片、简介等信息。同时,我们还可以使用Vue提供的过滤器来格式化数据,比如将日期格式化成指定的格式。 另外,为了提高用户体验,我们可以在详情页面中添加一些交互功能。比如,用户可以在详情页面中点击一个按钮来展示更多的详细信息,或者可以添加产品到购物车等。 最后,在实现这个demo的过程中,我们可以使用Vue的路由功能来实现列表页面和详情页面之间的切换。通过定义路由规则,当用户访问某一个特定的路径时,可以展示对应的页面。 总之,Vue详情页demo可以通过展示产品或者内容的详细信息来提供更好的用户体验。通过使用Vue的指令、插值语法、过滤器和路由功能,可以方便地实现这个功能。最终的效果是用户可以在列表页面中选择任意一项,然后进入详情页面查看更多的详细信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值