持续更新
- 020 vue3.0自定义指令实现一键复制
- 019 h5 draggable属性实现拖拽
- 018 自定义拖拽指令
- 017 uniapp微信小程序中自定义轮播图小圆点
- 016 二级分类选择
- 015 vue 三秒倒计时跳转页面
- 014 vue真机调试vsconsole
- 013 VUE 实现一键复制文字到粘贴板
- 012 VUE 实现无痕刷新页面
- 011 时间戳转正常日期
- 010 vue自定义倒计时组件
- 009 vant实现上拉刷新下拉加载
- 008 Vue简单实现全选全不选按钮
- 007vue-简单实现单选按钮
- 006 vue后台管理系统表格elementui
- 005短信验证码60倒计时
- 004 element ui 中 el-upload 组件 用自定义函数覆盖
- 003 简单版购物车
- 002 tab切换
- 001 todolist简陋版
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>