Browse Source

增加面包屑组件、图标组件

develop
zq 2 days ago
parent
commit
45e523f713
  1. 33
      build/webpack.config.js
  2. 2
      examples/src/App.vue
  3. 907
      package-lock.json
  4. 7
      packages/Breadcrumb/index.js
  5. 160
      packages/Breadcrumb/src/index.vue
  6. 7
      packages/SvgIcon1/index.js
  7. 175
      packages/SvgIcon1/src/index.vue
  8. 1
      packages/assets/bind_sites.svg
  9. 1
      packages/assets/home-bread.svg
  10. BIN
      packages/assets/separator.png
  11. 10
      packages/index.js
  12. 5
      postcss.config.js

33
build/webpack.config.js

@ -6,7 +6,7 @@ const {
module.exports = { module.exports = {
mode: 'production', mode: 'production',
stats: 'verbose', // stats: 'verbose',
entry: { entry: {
'zhicheng-components': './packages/index.js' 'zhicheng-components': './packages/index.js'
}, },
@ -40,13 +40,32 @@ module.exports = {
}, },
{ {
test: /\.scss$/, test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', { use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'sass-loader', loader: 'sass-loader',
options: { options: {
implementation: require('sass') // 显式指定 sass implementation: require('sass'),
sassOptions: {
// fibers: require('fibers'), // 不再需要
fibers:false,
outputStyle: 'compressed',
quietDeps: true // 忽略警告
} }
}] }
}
]
}, },
// {
// test: /\.scss$/,
// use: [MiniCssExtractPlugin.loader, 'css-loader', {
// loader: 'sass-loader',
// options: {
// implementation: require('sass') // 显式指定 sass
// }
// }]
// },
{ {
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
use: [{ use: [{
@ -80,7 +99,8 @@ module.exports = {
}) })
], ],
optimization: { optimization: {
splitChunks: false splitChunks: false,
minimize: false // 临时关闭压缩
}, },
externals: { externals: {
vue: { vue: {
@ -89,5 +109,8 @@ module.exports = {
commonjs2: 'vue', commonjs2: 'vue',
amd: 'vue' amd: 'vue'
} }
},
stats: {
warningsFilter: () => true // 过滤所有警告
} }
} }

2
examples/src/App.vue

@ -81,6 +81,8 @@
@input="handleInput" @focus="handleInput" placeholder="这是自定义默认提示语" /> @input="handleInput" @focus="handleInput" placeholder="这是自定义默认提示语" />
<div style="width: 20px;height: 10px;"></div> <div style="width: 20px;height: 10px;"></div>
<GuipInput ref="GuipInput" width="133px" label="售价" placeholder="请输入售价"
unit="元"></GuipInput>
<GuipInput v-model="form.input3" width="400px"> <GuipInput v-model="form.input3" width="400px">
<span slot="prependshow">http:</span> <span slot="prependshow">http:</span>

907
package-lock.json

File diff suppressed because it is too large

7
packages/Breadcrumb/index.js

@ -0,0 +1,7 @@
import Breadcrumb from './src/index.vue'
Breadcrumb.install = function(Vue) {
Vue.component(Breadcrumb.name || 'Breadcrumb', Breadcrumb)
}
export default Breadcrumb

160
packages/Breadcrumb/src/index.vue

@ -0,0 +1,160 @@
<template>
<div v-if="breadcrumbs.length > 0" class="breadcrumb-container flex-between">
<nav>
<ol class="breadcrumb">
<li
v-for="(item, index) in breadcrumbs"
:key="index"
class="breadcrumb-item"
:class="{ active: index === breadcrumbs.length - 1 }"
>
<template v-if="index !== breadcrumbs.length - 1">
<router-link to="/" v-if="item.title == '首页'">
<SvgIcon1 :iconPath="require(`../../assets/home-bread.svg`)" defaultColor="#8A9099" :size="16" activeColor="#006AFF"/>
</router-link>
<router-link v-else :to="item.path">{{ item.title }}</router-link>
<img class="separator" src="../../assets/separator.png" alt="">
</template>
<template v-else>
<span>{{ item.title }}</span>
</template>
</li>
</ol>
</nav>
<div v-if="breadRightText" class="gap8 breadRight">
<img class="ml-8" src="../../assets/bind_sites.svg" alt="" />
站点简称<a :href="breadRightText">{{ breadRightText }}</a>
</div>
</div>
</template>
<script>
import SvgIcon1 from '../..//SvgIcon1';
export default {
name: 'Breadcrumb',
components: {
SvgIcon1,
},
computed: {
breadcrumbs() {
if (this.$route.meta.hideBreadcrumb) return [];
const crumbs = [];
let currentRoute = this.$route;
//
while (currentRoute) {
//
// const matchedRoute = this.$router.options.routes.find(
// r => r.name === currentRoute.name
// );
//
const routeWithParams = {
path: currentRoute.path,
query: currentRoute.query,
params: currentRoute.params
};
crumbs.unshift({
path: routeWithParams,
title: this.getTitle(currentRoute)
});
// meta.breadcrumbParent
if (currentRoute.meta.breadcrumbParent) {
currentRoute = this.$router.options.routes.find(
r => r.name === currentRoute.meta.breadcrumbParent
);
// $route
if (currentRoute) {
currentRoute = {
...currentRoute,
path: currentRoute.path,
query: this.$route.query, //
params: this.$route.params, //
meta: currentRoute.meta || {}
};
}
} else {
currentRoute = null;
}
}
return crumbs;
},
breadRightText() {
return this.$store && this.$store.state.breadRightText
}
},
methods: {
getTitle(route) {
return typeof route.meta.title === 'function'
? route.meta.title(route)
: route.meta.title || route.name;
}
}
};
</script>
<style scoped lang="scss">
/* 保持之前的样式不变 */
.breadcrumb-container {
padding: 16px 12px;
background-color: #f5f5f5;
border-radius: 4px;
.breadRight{
a{
text-decoration: none;
color: #006AFF;
}
}
}
.home-icon {
width: 16px;
height: 16px;
}
.breadcrumb {
display: flex;
flex-wrap: wrap;
height: 22px;
align-items: center;
padding: 0;
margin: 0;
list-style: none;
}
.breadcrumb-item {
display: flex;
align-items: center;
height: 100%;
cursor: pointer;
}
.router-link-active {
height: 100%;
display: flex;
align-items: center;
}
.breadcrumb-item a {
color: #626573;
text-decoration: none;
&:hover {
color: #006AFF;
}
}
.breadcrumb-item.active span {
color: #1E2226;
;
}
.separator {
width: 12px;
height: 12px;
}
</style>

7
packages/SvgIcon1/index.js

@ -0,0 +1,7 @@
import SvgIcon1 from './src/index.vue'
SvgIcon1.install = function(Vue) {
Vue.component(SvgIcon1.name || 'SvgIcon1', SvgIcon1)
}
export default SvgIcon1

175
packages/SvgIcon1/src/index.vue

@ -0,0 +1,175 @@
<template>
<div class="svg-icon-wrapper" :style="wrapperStyle" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
<div class="svg-icon" v-html="svgContent" :style="{
'--icon-color': (hoverEffect || isActive) ? activeColor : defaultColor,
'--icon-hover-color': activeColor
}"></div>
<!-- :style="iconStyle" -->
</div>
</template>
<script>
export default {
name: 'SvgIcon1',
props: {
//
iconPath: {
type: String,
required: true
},
//
defaultColor: {
type: String,
default: '#606266'
},
//
activeColor: {
type: String,
default: null
},
//
hoverEffect: {
type: Boolean,
default: false
},
//
size: {
type: [String, Number],
default: '14px'
},
//
isActive: {
type: Boolean,
default: false
}
},
data() {
return {
svgContent: '',
isHovering: false,
currentColor: this.defaultColor
}
},
computed: {
wrapperStyle() {
return {
width: typeof this.size === 'number' ? `${this.size}px` : this.size,
height: typeof this.size === 'number' ? `${this.size}px` : this.size,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center'
}
},
iconStyle() {
return {
width: '100%',
height: '100%',
color: this.currentColor,
transition: 'color 0.3s ease'
}
},
shouldChangeColor() {
return this.activeColor && (this.hoverEffect || this.isActive)
}
},
watch: {
isActive(newVal) {
console.log(newVal, 'newVal---');
if (this.shouldChangeColor) {
this.currentColor = newVal ? this.activeColor : this.defaultColor
console.log(this.currentColor, 'this.currentColor--');
}
},
defaultColor(newVal) {
if (!this.isHovering && !this.isActive) {
this.currentColor = newVal
}
},
activeColor() {
this.updateColorState()
}
},
methods: {
async loadSvg() {
try {
const response = await fetch(this.iconPath)
this.svgContent = await response.text()
this.processSvg()
} catch (error) {
console.error('Failed to load SVG:', error)
}
},
processSvg() {
// SVG便CSS
this.$nextTick(() => {
const svgElement = this.$el.querySelector('svg')
if (svgElement) {
//
svgElement.removeAttribute('fill')
svgElement.removeAttribute('style')
const paths = svgElement.querySelectorAll('path, circle, rect, polygon')
paths.forEach(el => {
el.removeAttribute('fill')
})
svgElement.style.fill = 'currentColor'
svgElement.style.width = '100%'
svgElement.style.height = '100%'
}
})
},
handleMouseEnter() {
this.isHovering = true
this.updateColorState()
},
handleMouseLeave() {
this.isHovering = false
this.updateColorState()
},
updateColorState() {
if (this.activeColor) {
if (this.isActive) {
this.currentColor = this.activeColor
} else {
this.currentColor = this.isHovering && this.hoverEffect ?
this.activeColor :
this.defaultColor
}
} else {
this.currentColor = this.defaultColor
}
}
},
created() {
this.loadSvg()
}
}
</script>
<style scoped>
.svg-icon-wrapper {
cursor: pointer;
}
.svg-icon {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: var(--icon-color);
transition: color 0.3s;
}
.svg-icon:hover {
color: var(--icon-hover-color);
}
.svg-icon {
display: inline-flex;
}
.svg-icon>>>svg {
fill: currentColor;
}
</style>

1
packages/assets/bind_sites.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="16" height="16" viewBox="0 0 16 16"><defs><clipPath id="master_svg0_166_49091"><rect x="0" y="0" width="16" height="16" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_166_49091)"><g><path d="M3.993058,2.326391373069763Q2.333333,3.986113373069763,2.333333,6.333333373069763Q2.333333,10.987083373069764,7.58354,15.187233373069763Q7.62755,15.222433373069762,7.67685,15.249733373069763Q7.72614,15.277133373069763,7.77933,15.295733373069764Q7.83251,15.314433373069763,7.88808,15.323833373069764Q7.94364,15.333333373069763,8,15.333333373069763Q8.05636,15.333333373069763,8.111930000000001,15.323833373069764Q8.16749,15.314433373069763,8.22067,15.295733373069764Q8.273859999999999,15.277133373069763,8.32315,15.249733373069763Q8.37245,15.222433373069762,8.41646,15.187233373069763Q13.6667,10.987083373069764,13.6667,6.333333373069763Q13.6667,3.986113373069763,12.00694,2.326391373069763Q10.34721,0.6666663730697632,8,0.6666663730697632Q5.65278,0.6666663730697632,3.993058,2.326391373069763ZM8,13.804833373069764Q3.666667,10.166283373069763,3.666667,6.333333373069763Q3.666667,4.538403373069763,4.9358699999999995,3.269203373069763Q6.20507,2.000000373069763,8,2.000000373069763Q9.79493,2.000000373069763,11.06413,3.269203373069763Q12.33333,4.538403373069763,12.33333,6.333333373069763Q12.33333,10.166293373069763,8,13.804833373069764Z" fill-rule="evenodd" fill="#8A9099" fill-opacity="1"/></g><g><path d="M6.114383,4.447716492279053Q5.333333,5.228765492279052,5.333333,6.333333492279053Q5.333333,7.437903492279053,6.114383,8.218953492279052Q6.895433,9.000003492279053,8,9.000003492279053Q9.104569999999999,9.000003492279053,9.88562,8.218953492279052Q10.66667,7.437903492279053,10.66667,6.333333492279053Q10.66667,5.228765492279052,9.88562,4.447716492279053Q9.104569999999999,3.666666492279053,8,3.666666492279053Q6.895432,3.666666492279053,6.114383,4.447716492279053ZM7.05719,7.276143492279052Q6.666667,6.885613492279052,6.666667,6.333333492279053Q6.666667,5.781053492279053,7.05719,5.390523492279053Q7.44772,5.000000492279053,8,5.000000492279053Q8.55228,5.000000492279053,8.94281,5.390523492279053Q9.33333,5.781053492279053,9.33333,6.333333492279053Q9.33333,6.885613492279052,8.94281,7.276143492279052Q8.55228,7.666663492279053,8,7.666663492279053Q7.44772,7.666663492279053,7.05719,7.276143492279052Z" fill-rule="evenodd" fill="#8A9099" fill-opacity="1"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

1
packages/assets/home-bread.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

BIN
packages/assets/separator.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

10
packages/index.js

@ -6,6 +6,8 @@ import GuipTextarea from './GuipTextarea'
import DevicePreview from './DevicePreview' import DevicePreview from './DevicePreview'
import GuipRadio from './GuipRadio' import GuipRadio from './GuipRadio'
import GuipSelect from './GuipSelect' import GuipSelect from './GuipSelect'
import Breadcrumb from './Breadcrumb'
import SvgIcon1 from './SvgIcon1'
import 'element-ui/lib/theme-chalk/index.css' // 如果依赖Element import 'element-ui/lib/theme-chalk/index.css' // 如果依赖Element
import './styles/index.css' // 全局引入 import './styles/index.css' // 全局引入
import './styles/common.scss' // 全局引入 import './styles/common.scss' // 全局引入
@ -18,7 +20,9 @@ const components = [
GuipTextarea, GuipTextarea,
DevicePreview, DevicePreview,
GuipRadio, GuipRadio,
GuipSelect GuipSelect,
Breadcrumb,
SvgIcon1
] ]
const install = function (Vue) { const install = function (Vue) {
@ -39,5 +43,7 @@ export default {
GuipTextarea, GuipTextarea,
DevicePreview, DevicePreview,
GuipRadio, GuipRadio,
GuipSelect GuipSelect,
Breadcrumb,
SvgIcon1
} }

5
postcss.config.js

@ -0,0 +1,5 @@
module.exports = {
plugins: [
require('autoprefixer')({ grid: true })
]
}
Loading…
Cancel
Save