文献综述不是“文献的堆砌”,是“学术对话的入场券”:毕夏AI如何帮你把“报菜名”变成“有脑子的梳理”
2026/8/29 13:43:11
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| containerClass | 加载条容器的类名 | string | undefined |
| containerStyle | 加载条容器的样式 | CSSProperties | {} |
| loadingBarSize | 加载条大小,单位px | number | 2 |
| colorLoading | 加载中颜色 | string | undefined |
| colorFinish | 加载完成颜色 | string | undefined |
| colorError | 加载错误颜色 | string | ‘#ff4d4f’ |
| to | 加载条的挂载位置,可选:元素标签名(例如body)或者元素本身,false 会待在原地 | string | HTMLElement | false | ‘body’ |
| 名称 | 说明 | 类型 |
|---|---|---|
| start | 开始加载的回调函数 | (from = 0, to = 80) => void |
| finish | 结束加载的回调函数 | () => void |
| error | 出现错误的回调函数 | () => void |
其中引入使用了以下工具函数:
<script setup lang="ts">import{ref,computed,watch,nextTick}from'vue'importtype{CSSProperties}from'vue'import{useInject}from'components/utils'exportinterfaceProps{containerClass?:string// 加载条容器的类名containerStyle?:CSSProperties// 加载条容器的样式loadingBarSize?:number// 加载条大小,单位 pxcolorLoading?:string// 加载中颜色colorFinish?:string// 加载完成颜色colorError?:string// 加载错误颜色to?:string|HTMLElement|false// 加载条的挂载位置,可选:元素标签名(例如 body)或者元素本身,false 会待在原地}constprops=withDefaults(defineProps<Props>(),{containerClass:undefined,containerStyle:()=>({}),loadingBarSize:2,colorLoading:undefined,colorFinish:undefined,colorError:'#ff4d4f',to:'body'})constinitialDisplay=ref<boolean>(false)// 性能优化,使用 v-if 避免初始时不必要的渲染,展示之后使用 v-show 来控制显示隐藏constshowLoadingBar=ref<boolean>(false)// 加载条是否显示constloadingBarRef=ref()// 加载条元素引用consttransitionDisabled=ref(false)// 是否禁用过渡,表示使用仅由 JavaScript 执行的动画constloadingStarted=ref<boolean>(false)// 加载条是否开始constloadingFinishing=ref<boolean>(false)// 加载条是否完成constloadingErroring=ref<boolean>(false)// 加载条是否报错const{colorPalettes}=useInject('LoadingBar')// 主题色注入constcolorLoadingComputed=computed(()=>{if(props.colorLoading===undefined){returncolorPalettes.value[5]}else{returnprops.colorLoading}})constcolorFinishComputed=computed(()=>{if(props.colorFinish===undefined){returncolorPalettes.value[5]}else{returnprops.colorFinish}})watch(showLoadingBar,(to)=>{if(to&&!initialDisplay.value){initialDisplay.value=true}},{immediate:true})asyncfunctioninit():Promise<void>{showLoadingBar.value=falseloadingFinishing.value=falseloadingErroring.value=falsetransitionDisabled.value=trueawaitnextTick()transitionDisabled.value=false}// 加载条开始加载的回调函数asyncfunctionstart(from=0,to=80,status:'starting'|'error'='starting'):Promise<void>{loadingStarted.value=trueawaitinit()if(loadingFinishing.value){return}showLoadingBar.value=trueawaitnextTick()if(!loadingBarRef.value){return}loadingBarRef.value.style.transition='none'// 禁用过渡loadingBarRef.value.style.maxWidth=`${from}%`voidloadingBarRef.value.offsetWidth// 触发浏览器回流(重排)loadingBarRef.value.className=`loading-bar loading-bar-${status}`loadingBarRef.value.style.transition=''loadingBarRef.value.style.maxWidth=`${to}%`}// 加载条结束加载的回调函数asyncfunctionfinish():Promise<void>{if(loadingFinishing.value||loadingErroring.value){return}if(loadingStarted.value){awaitnextTick()}loadingFinishing.value=trueif(!loadingBarRef.value){return}loadingBarRef.value.className='loading-bar loading-bar-finishing'loadingBarRef.value.style.maxWidth='100%'voidloadingBarRef.value.offsetWidth// 触发浏览器回流(重排)showLoadingBar.value=false}// 加载条出现错误的回调函数functionerror():void{if(loadingFinishing.value||loadingErroring.value){return}if(!showLoadingBar.value){voidstart(100,100,'error').then(()=>{loadingErroring.value=true})}else{loadingErroring.value=trueif(!loadingBarRef.value){return}loadingBarRef.value.className='loading-bar loading-bar-error'loadingBarRef.value.style.maxWidth='100%'voidloadingBarRef.value.offsetWidth showLoadingBar.value=false}}functiononAfterEnter():void{if(loadingErroring.value){showLoadingBar.value=false}}asyncfunctiononAfterLeave():Promise<void>{awaitinit()}defineExpose({start,finish,error})</script><template><Teleport:disabled="to === false":to="to === false ? null : to"><Transition name="fade-in"appear@after-enter="onAfterEnter"@after-leave="onAfterLeave":css="!transitionDisabled"><div v-if="initialDisplay"v-show="showLoadingBar"class="loading-bar-wrap":class="containerClass":style="[`--loading-bar-size:${loadingBarSize}px; --loading-bar-color-loading:${colorLoadingComputed}; --loading-bar-color-finish:${colorFinishComputed}; --loading-bar-color-error:${colorError};`,containerStyle]"><div ref="loadingBarRef"class="loading-bar"style="max-width: 100%"></div></div></Transition></Teleport></template><style lang="less"scoped>.fade-in-enter-active{transition:all0.3s cubic-bezier(0.4,0,0.2,1);}.fade-in-leave-active{transition:all0.8s cubic-bezier(0.4,0,0.2,1);}.fade-in-enter-from,.fade-in-leave-to{opacity:0;}.loading-bar-wrap{position:fixed;top:0;left:0;right:0;z-index:9999;height:var(--loading-bar-size);.loading-bar{width:100%;transition:max-width 4s linear,background0.2s linear;height:var(--loading-bar-size);border-radius:var(--loading-bar-size);}.loading-bar-starting{background:var(--loading-bar-color-loading);}.loading-bar-finishing{background:var(--loading-bar-color-finish);transition:max-width0.2s linear,background0.2s linear;}.loading-bar-error{background:var(--loading-bar-color-error);transition:max-width0.2s linear,background0.2s linear;}}</style>其中引入使用了以下组件:
<script setup lang="ts">importLoadingBarfrom'./LoadingBar.vue'import{ref}from'vue'constloadingBar=ref()constdisabled=ref(true)constlocalCardRef=ref()constlocalLoadingBar=ref()constcustomLoadingBar=ref()functionhandleStart(){loadingBar.value.start()disabled.value=false}functionhandleFinish(){loadingBar.value.finish()disabled.value=true}functionhandleError(){disabled.value=trueloadingBar.value.error()}</script><template><div><h1>{{$route.name}}{{$route.meta.title}}</h1><h2class="mt30 mb10">基本使用</h2><Space><Button type="primary"@click="handleStart">开始</Button><Button:disabled="disabled"@click="handleFinish">结束</Button><Button type="danger"@click="handleError">报个错</Button></Space><LoadingBar ref="loadingBar"/><h2class="mt30 mb10">局部加载条</h2><divclass="card-container"ref="localCardRef"><Space><Button type="primary"@click="localLoadingBar.start()">Start</Button><Button@click="localLoadingBar.finish()">Finish</Button><Button type="danger"@click="localLoadingBar.error()">Error</Button></Space></div><LoadingBar ref="localLoadingBar":container-style="{ position: 'absolute' }":to="localCardRef"/><h2class="mt30 mb10">自定义加载条样式</h2><Space><Button type="primary"@click="customLoadingBar.start()">Start</Button><Button@click="customLoadingBar.finish()">Finish</Button><Button type="danger"@click="customLoadingBar.error()">Error</Button></Space><LoadingBar ref="customLoadingBar":loading-bar-size="5"color-loading="#2db7f5"color-finish="#52c41a"color-error="magenta"/></div></template><style lang="less"scoped>.card-container{position:relative;display:flex;align-items:center;height:200px;padding:16px 24px;border:1px solid #d9d9d9;}</style>