Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,525 changes: 3,403 additions & 122 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"ts-jest": "^29.0.5",
"tslib": "^2.5.0",
"typescript": "^4.9.5",
"url-loader": "^4.1.1",
"vue": "^3.2.47",
"vue-loader": "^17.0.1",
"vue-template-compiler": "^2.7.14",
Expand All @@ -77,6 +78,8 @@
"dependencies": {
"@types/uuid": "^9.0.1",
"framer-motion": "^8.5.5",
"mockjs": "^1.1.0",
"svg-sprite-loader": "^6.0.11",
"uuid": "^9.0.0"
}
}
}
17 changes: 17 additions & 0 deletions vue/assets/image/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

import SvgIcon from '@/components/SvgIcon/index.vue'

const req = require.context('@/assets/image',false,/\.svg$/)
const requireAll = requireContext =>{
requireContext.keys().map(requireContext)
}
requireAll(req)


const svgIcon = {
install(vue) {
vue.component('svg-icon', SvgIcon)
}
}

export default svgIcon
1 change: 1 addition & 0 deletions vue/assets/image/next.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions vue/assets/image/prev.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions vue/assets/image/search.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions vue/assets/image/sort.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
102 changes: 102 additions & 0 deletions vue/components/LoadImage/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<template>
<div class="load-image">
<div class="image-wrapper" ref="loadImage">
<img
v-for="(url, index) in imageUrl" :key="index"
:src="url"
class="img"
:style="{width: imgWidth, height: imgHeight}"
/>
</div>
</div>
</template>

<script>
export default {
name:'LoadImage',
components:{

},
props: {
urls:Array,
imgWidth: {
type:String,
default: '100%'
},
imgHeight:{
type:String,
default: '500px'
},
preloadNumber:{
type:Number,
default: 3
}
},
data() {
return {
imageUrl:[]
}
},
created(){
this.imageUrl = this.urls.slice(0,this.preloadNumber)
},
mounted(){
this.$refs.loadImage.addEventListener('scroll',this.debounce(this.handleScroll),1000)
},
destroyed(){
this.$refs.loadImage.removeEventListener('scroll',this.debounce(this.handleScroll),1000)
},
methods: {
addImage(){
// 添加或请求图片
const length = this.imageUrl.length
const addImg = this.urls[length]
if(length<this.urls.length ){
this.imageUrl.push(addImg)
}
},

handleScroll() {
// 滚动条滚过的距离
const scrollTop = this.$refs.loadImage.scrollTop
// loadImage 组件的可视高度
const clientHeight = this.$refs.loadImage.clientHeight
// 滚动条长度
const scrollHeight = this.$refs.loadImage.scrollHeight

// 当滚动过的距离+可视区的高度>=滚动条长度时,相当于滚动到了底部
if (scrollTop + clientHeight >= scrollHeight) {
// 触底,添加图片
this.addImage()
}


},

// 防抖优化触底加载
debounce(fn, delay) {
let timer = null
return function (...arg) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arg)
}, delay);
}
}
},
}
</script>

<style lang='less' scoped>
.load-image {
.image-wrapper {
height: 100%;
overflow: auto;
.img {
display: block;
margin: 10px 0;
}
}

}
</style>
135 changes: 135 additions & 0 deletions vue/components/Pagination/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<template>
<div class="pagination">
<!-- 上一页 -->
<div
:disabled="curPage === 1"
:class="{ disabled: curPage === 1 }"
@click="setCurrentPage(curPage - 1)"
>
<svg-icon iconFileName="prev"></svg-icon>
</div>
<!-- 起始页 -->
<div v-show="startEnd.start > 1" @click="setCurrentPage(1)">1</div>
<div class="disabled" v-show="startEnd.start > 2">...</div>
<!-- 连续页码 -->
<div
v-for="item in startEndArr"
:key="item"
:class="{ active: item === curPage }"
@click="setCurrentPage(item)"
>
{{ item }}
</div>
<div class="disabled" v-show="startEnd.end < totalPage - 1">...</div>
<!-- 最后一页 -->
<div v-show="startEnd.end < totalPage" @click="setCurrentPage(totalPage)">
{{ totalPage }}
</div>
<div
:disabled="curPage === totalPage"
:class="{ disabled: curPage === totalPage }"
@click="setCurrentPage(curPage + 1)"
>
<svg-icon iconFileName="next"></svg-icon>
</div>
<div class="total">共 {{ total }} 条</div>
</div>
</template>

<script>
export default {
name: "Pagination",
props: {
currentPage: {
type: Number,
default: 1,
},
total: {
type: Number,
default: 0,
},
pageSize: {
type: Number,
default: 10,
},
},

data() {
return {
curPage: this.currentPage,
continues: 3
};
},
computed: {
totalPage() {
const { total, pageSize } = this
return Math.ceil(total / pageSize)
},
// 获取连续页码,设置页码 ...
startEnd() {
const { curPage, continues, totalPage } = this
let start, end
start = curPage - Math.floor(continues / 2);
if (start < 1) {
start = 1
}
end = start + continues - 1;
if (end > totalPage) {
end = totalPage
start = end - continues + 1;
if (start < 1) {
start = 1
}
}
return { start, end };
},
startEndArr(){
const arr = []
const {start, end} = this.startEnd
for(let page = start; page <= end; page++){
arr.push(page)
}
return arr
}
},
methods: {
// 切换页码
setCurrentPage(page) {
if (page === this.curPage) return
if(page > this.totalPage) return
if(page <= 0 ) return
this.curPage = page;
this.$emit("currentChange", page)
},
},

};
</script>
<style lang="less" scoped>
.pagination {
margin: 20px;
text-align: center;
div {
display: inline-block;
margin: 0 8px;
vertical-align: top;
font-size: 14px;
height: 28px;
line-height: 28px;
text-align: center;
cursor: pointer;
&.active {
font-weight: 600;
color: #258aff;
}
&.disabled {
cursor: not-allowed;
color: #ccc;
}
}
.total {
display: inline-block;
line-height: 28px;
}
}
</style>
107 changes: 107 additions & 0 deletions vue/components/Popover/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<template>
<div class="popover" @mouseenter="handleMouseEnter($event)" @mouseleave="handleMouseLeave">
<!-- popover 触发 -->
<div @click="handleClick($event)" class="popover-item">
<slot ></slot>
</div>
<!-- popover 提示内容 -->
<div class="popover-content" :style="{ top: clientY+'px', left:clientX+'px' }" v-show="popoverVisible" ref="popoverContent" @click="($event)=>{$event.stopPropagation()}">
<div class="popover-title">{{ title }}</div>
<div v-html="content"></div>
</div>
</div>
</template>

<script>
export default {
name:'Popover',
props:{
content: String,
title: {
type: String,
default: 'Title'
},
trigger:{
type:String,
default:'click'
}
},
data() {
return {
popoverVisible: false,
clientY:0,
clientX:0,
}
},
mounted() {
window.addEventListener('click', this.handleCancelPopover)
},
destroyed() {
window.removeEventListener('click',this.handleCancelPopover)
},
methods: {
handleClick(e){
e.stopPropagation();
this.popoverVisible = !this.popoverVisible
const width = e.target.clientWidth
const itemCenter = e.target.offsetLeft + width/2 // 计算元素的中间点距浏览器的x轴位置
const itemTop = e.target.offsetTop // 计算元素距浏览器的顶部位置
this.$nextTick(()=>{
const contentCenter = this.$refs.popoverContent.offsetWidth // 提示框的自身宽度
const contentHeight = this.$refs.popoverContent.offsetHeight // 提示框的自身高度
this.clientX = itemCenter - contentCenter/2
this.clientY = itemTop - contentHeight -15
})
},
handleMouseEnter(e){
if(this.trigger === 'hover'){
this.handleClick(e)
}
},
handleCancelPopover() {
this.$nextTick(()=>{
if(this.popoverVisible){
this.popoverVisible = false
}
})
},
handleMouseLeave(e){
if(this.trigger === 'hover'){
this.handleCancelPopover()
}
}

},
}
</script>

<style lang='less' scoped>
.popover {
&-content {
position: absolute;
padding: 12px;
min-width: 100px;
background-color: #fff;
border: 1px solid #ebeef5;
border-radius: 8px;
box-shadow: 0 6px 16px 0 rgb(0 0 0 / 8%), 0 3px 6px -4px rgb(0 0 0 / 12%);
// 倒三角通过 filter滤镜 实现三角形的阴影效果
&:after {
content: '';
position: absolute;
width: 0;
height: 0;
bottom: -20px;
left: 0;
right: 0;
margin: auto;
border: 10px solid;
border-color: #fff transparent transparent;
filter: drop-shadow( 0 6px 16px 0 rgb(0 0 0 / 8%));
}
}
&-title {
font-weight: 700;
}
}
</style>
Loading