第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 的使用
递归的使用
无限层级菜单如何实现
进度条
改变进度实现动态进度条
时间选择器
开始时间和结束时间设置
开始时间和结束时间联动
分发事件
日期选择器
开始日期和结束日期设置
开始日期和结束日期联动
分发事件
城市选择器
需求分析
获取城市数据
组件组合式使用
按城市选择逻辑
按省份选择逻辑
点击跳转位置
分发事件