第4章 封装组件中级篇

1.导航菜单

2.进度条(progress)

--components/progress
	--src/index.vue
	--index.ts

src/index.vue

<template>
  <el-progress :percentage="p" v-bind="$attrs"></el-progress>
</template>

<script lang='ts' setup>
import { onMounted, ref } from 'vue'

// 标识动画加载过程中改变的值
let num = ref<number>(0)

let props = defineProps({
  // 进度条进度
  percentage: {
    type: Number,
    required: true
  },
  // 是否有动画效果
  isAnimate: {
    type: Boolean,
    default: false
  },
  // 动画时长(毫秒)
  time: {
    type: Number,
    default: 3000
  },
})

let p = ref(0)

onMounted(() => {
  if (props.isAnimate) {
    // 规定时间内加载完成
    let t = Math.ceil(props.time / props.percentage)
    let timer = setInterval(() => {
      p.value += 1
      if (p.value >= props.percentage) {
        p.value = props.percentage
        clearInterval(timer)
      }
    }, t)
  }
})
</script>

<style lang='scss' scoped>
</style>

index.ts

import { App } from 'vue'
import progress from './src/index.vue'

// 让这个组件可以通过use的形式使用
export default {
  install(app: App) {
    app.component('m-progress', progress)
  }
}

修改components/index.ts中的文件

import { App } from 'vue'
import progress from './progress'

const components = [
  progress
]

export default {
  install(app: App) {
    components.map(item => {
      app.use(item)
    })
  }
}

在vieew/progress/index.vue中使用
vieew/progress/index.vue

<template>
  <div>
    <m-progress isAnimate :percentage="60"></m-progress>
    <br />
    <m-progress isAnimate status="success" :stroke-width="20" :percentage="60"></m-progress>
    <br />
    <m-progress :time="5000" type="circle" isAnimate :percentage="60"></m-progress>
  </div>
</template>

<script lang='ts' setup>
</script>

<style lang='scss' scoped>
</style>

3.时间选择器(chooseTime)

-- components/chooseTime
	--src/index.vue
	--index.ts

src/index.vue

<template>
  <div style="display: flex;">
    <div style="margin-right: 20px;">
      <el-time-select
        v-model="startTime"
        :placeholder="startPlaceholder"
        :start="startTimeStart"
        :step="startStep"
        :end="startTimeEnd"
        v-bind="$attrs.startOptions"
      ></el-time-select>
    </div>
    <div>
      <el-time-select
        v-model="endTime"
        :min-time="startTime"
        :placeholder="endPlaceholder"
        :start="endTimeStart"
        :step="endStep"
        :end="endTimeEnd"
        :disabled="endTimeDisabled"
        v-bind="$attrs.endOptions"
      ></el-time-select>
    </div>
  </div>
</template>

<script lang='ts' setup>
import {ref, watch} from 'vue'

let props = defineProps({
  // 开始时间的占位符
  startPlaceholder: {
    type: String,
    default: '请选择开始时间'
  },
  // 结束时间的占位符
  endPlaceholder: {
    type: String,
    default: '请选择结束时间'
  },
  // 开始时间的开始选择
  startTimeStart: {
    type: String,
    default: "08:00"
  },
  // 开始时间的步进
  startStep: {
    type: String,
    default: "00:30"
  },
  // 开始时间的结束选择
  startTimeEnd: {
    type: String,
    default: "24:00"
  },
  // 结束时间的开始选择
  endTimeStart: {
    type: String,
    default: "08:00"
  },
  // 结束时间的步进
  endStep: {
    type: String,
    default: "00:30"
  },
  // 结束时间的结束选择
  endTimeEnd: {
    type: String,
    default: "24:00"
  },
})

let emits = defineEmits(['startChange', 'endChange'])

// 开始时间
let startTime = ref<string>('')
// 结束时间
let endTime = ref<string>('')
// 是否禁用结束时间
let endTimeDisabled = ref<boolean>(true)

// 监听开始时间的变化
watch(() => startTime.value, val => {
  if (val === '') {
    endTime.value = ''
    endTimeDisabled.value = true
  }
  else {
    endTimeDisabled.value = false
    // 给父组件分发事件
    emits('startChange', val)
  }
})

// 监听结束时间的变化
watch(() => endTime.value, val => {
  if (val !== '') {
    emits('endChange', {
      startTime: startTime.value,
      endTime: val
    })
  }
})
</script>

<style lang='scss' scoped>
</style>

index.ts

import { App } from 'vue'
import chooseTime from './src/index.vue'

// 让这个组件可以通过use的形式使用
export default {
  install(app: App) {
    app.component('m-choose-time', chooseTime)
  }
}

修改components/index.ts中的文件

import { App } from 'vue'
import chooseTime from './chooseTime'

const components = [
  chooseTime
]

export default {
  install(app: App) {
    components.map(item => {
      app.use(item)
    })
  }
}

在views/chooseTime/index.vue中使用

<template>
  <div>
    <m-choose-time :startOptions="startOptions" @startChange="startChange" @endChange="endChange"></m-choose-time>
    <br />
    <br />
  </div>
</template>

<script lang='ts' setup>
interface endValue {
  startTime: string,
  endTime: string
}
interface dateEndValue {
  startDate: Date,
  endDate: Date
}
let startChange = (val: string) => {
  console.log('startChange', val)
}
let endChange = (val: endValue) => {
  console.log('endChange', val)
}
let startOptions = {
  // size: 'mini',
  // clearable: false
}
</script>

<style lang='scss' scoped>
</style>

4.日期选择器(chooseDate)

--components/chooseDate
	--src/index.vue
	--index.js

src/index.vue

<template>
  <div style="display: flex;">
    <div style="margin-right: 20px;">
      <el-date-picker
        v-model="startDate"
        type="date"
        :placeholder="startPlaceholder"
        :disabledDate="startDisabledDate"
        v-bind="$attrs.startOptions"
      ></el-date-picker>
    </div>
    <div>
      <el-date-picker
        v-model="endDate"
        type="date"
        :placeholder="endPlaceholder"
        :disabled="endDateDisabled"
        :disabledDate="endDisabledDate"
        v-bind="$attrs.endOptions"
      ></el-date-picker>
    </div>
  </div>
</template>

<script lang='ts' setup>
import { ref, watch } from 'vue'

let props = defineProps({
  // 开始日期的占位符
  startPlaceholder: {
    type: String,
    default: '请选择开始日期'
  },
  // 结束日期的占位符
  endPlaceholder: {
    type: String,
    default: '请选择结束日期'
  },
  // 是否禁用选择今天之前的日期
  disableToday: {
    type: Boolean,
    default: true
  }
})

let emits = defineEmits(['startChange', 'endChange'])

// 开始日期
let startDate = ref<Date | null>(null)
// 结束日期
let endDate = ref<Date | null>(null)
// 控制结束日期的禁用状态
let endDateDisabled = ref<boolean>(true)

// 禁用开始日期的函数
let startDisabledDate = (time: Date) => {
  if (props.disableToday) return time.getTime() < Date.now() - 1000 * 60 * 60 * 24
}
// 禁用结束日期的函数
let endDisabledDate = (time: Date) => {
  if (startDate.value) {
    return time.getTime() < startDate.value.getTime() + 1000 * 60 * 60 * 24
  }
}

// 监听开始的日期
watch(() => startDate.value, val => {
  if (!val) {
    endDateDisabled.value = true
    endDate.value = null
  } else {
    emits('startChange', val)
    endDateDisabled.value = false
  }
})
// 监听结束的日期
watch(() => endDate.value, val => {
  if (val) {
    emits('endChange', {
      startDate: startDate.value,
      endDate: val
    })
  }
})
</script>

<style lang='scss' scoped>
</style>

index.ts

import { App } from 'vue'
import chooseDate from './src/index.vue'

// 让这个组件可以通过use的形式使用
export default {
  install(app: App) {
    app.component('m-choose-date', chooseDate)
  }
}

修改components/index.ts中的文件

import { App } from 'vue'
import chooseDate from './chooseDate'

const components = [
  chooseDate
]

export default {
  install(app: App) {
    components.map(item => {
      app.use(item)
    })
  }
}

在项目中使用:views/chooseDate


<template>
  <div>
    <m-choose-date :disableToday="false" :startOptions="startOptions" @startChange="dateStartChange" @endChange="dateEndChange"></m-choose-date>
  </div>
</template>

<script lang='ts' setup>
interface endValue {
  startTime: string,
  endTime: string
}
interface dateEndValue {
  startDate: Date,
  endDate: Date
}
let dateStartChange = (val: Date) => {
  console.log(val)
}
let dateEndChange = (val: dateEndValue) => {
  console.log(val)
}
let startOptions = {
  // size: 'mini',
  // clearable: false
}
</script>

<style lang='scss' scoped>
</style>

5.城市选择器(chooseCity)

6.总结

导航菜单
需求分析
数据设计
二级菜单如何实现
集成更多属性
tsx 的使用
递归的使用
无限层级菜单如何实现
进度条
改变进度实现动态进度条
时间选择器
开始时间和结束时间设置
开始时间和结束时间联动
分发事件
日期选择器
开始日期和结束日期设置
开始日期和结束日期联动
分发事件
城市选择器
需求分析
获取城市数据
组件组合式使用
按城市选择逻辑
按省份选择逻辑
点击跳转位置
分发事件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值