发财UI 开发日志

[发财UI] 开发日志

Vue3中的props和attributes

1
<Button @click="click">按钮</Button>

Vue3中默认会将外部的@click="click"传给组件的最外层元素,也就是<button></button>

1
2
3
4
5
6
<template>
<button :class="classes" :disabled="disabled" class="rich-button">
<span v-if="loading" class="rich-loadingIndicator"></span>
<slot/>
</button>
</template>

属性绑定

通过inheritAttrs可以选择是否继承组件外部的属性

1
2
3
4
5
6
7
8
9
10
<template>
<button>按钮</button>
</template>

<script lang="ts">
export default {
inheritAttrs:false //button不再继承外部属性
}
</script>

通过$attrs绑定外部属性

1
2
3
4
5
<template>
<div> //默认属性会继承到div上
<button v-bind="$attrs">按钮</button> //手动将属性绑定到button上
</div>
</template>

部分绑定属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<Button @click="click" size="" xxx="xxx">按钮</Button>

<template>
<div :size="size"> //将size绑定到div上
<button v-bind="rest">按钮</button> //将rest绑定到button上
</div> //rest包含了click和xxx属性
</template>

<script lang="ts">
export default {
setup(props, context){
const {size, ...rest} = context.attrs //将继承的属性分为两个部分
return {size, rest} //一部分是size,一部分是rest
}
}
</script>

props VS attrs

1、props 要先声明才能取值,attrs 不用先声明

2、props 声明过的属性,attrs 里不会再出现

3、props 不包含事件,attrs 包含

4、props 支持 string 以外的类型,attrs 只有 string 类型

项目开发中的CSS原则

  1. 组件的CSS不能用scoped

  2. 每个CSS的类最好加上前缀,防止相互覆盖

  3. CSS最小影响原则

如何做loading动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.rich-loadingIndicator {
width: 14px;
height: 14px;
display: inline-block;
margin-right: 4px;
border-radius: 8px;
border-color: $button-blue $button-blue $button-blue transparent;
border-style: solid;
border-width: 2px;
animation: rich-spin 1s infinite linear;
}

@keyframes rich-spin {
0% {
transform: rotate(0deg)
}
100% {
transform: rotate(360deg)
}

具名插槽

slot一个name,就可以精准的确定slot对应的内容

1
2
3
4
5
6
7
<header>
<slot name="title"/>
<span class="rich-dialog-close" @click="close"></span>
</header>
<main>
<slot name="content"/>
</main>
1
2
3
4
5
6
7
8
<template v-slot:content>
<strong>hi</strong>
<div>hi2</div>
</template>
<template v-slot:title>
<strong>加粗的标题</strong>
</template>

Teleport 传送标签

<Teleport to="目的地"></Teleport>中的内容会被挂载到目的地下

1
2
3
4
5
<template>
<Teleport to="body">
...
</Teleport>
</template>

Tabs

用JS获取插槽内容

1
const defaults = context.slots.default()

在运行时确认子组件的类型

1
2
3
4
5
defaults.forEach(tag => {
if (tag.type !== Tab) {
throw new Error('Tabs的子组件必须是Tab');
}
});

getBoundingClientRect()

Element.getBoundingClientRect() 方法返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口的位置。

1
const {width,height,top,left} = el.getBoundingClientRect()

异步加载

1
2
3
4
5
6
7
setup(props) {  
const content = ref<string>('')
import(props.path).then(result => {
content.value = result.default
})
return {content}
}

Custom Blocks

首先需要先配置好vite

vite.config.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import * as fs from 'fs'
import {baseParse} from '@vue/compiler-core'

export default {
vueCustomBlockTransforms: {
demo: (options) => {
const {code, path} = options
const file = fs.readFileSync(path).toString()
const parsed = baseParse(file).children.find(n => n.tag === 'demo')
const title = parsed.children[0].content
const main = file.split(parsed.loc.source).join('').trim()
return `export default function (Component) {
Component.__sourceCode = ${
JSON.stringify(main)
}
Component.__sourceCodeTitle = ${JSON.stringify(title)}
}`.trim()
}
}
};

在需要变为demo的文件开头加上<demo>Title</demo>

1
2
3
4
5
6
7
8
9
10
<demo>
常规使用
</demo>
<template>
<div>
<Button>你好</Button>
<Button theme="link">你好</Button>
<Button theme="text">你好</Button>
</div>
</template>

就可以在引用该demo的组件中使用相关的api

1
2
3
const Title = component.__sourceCodeTitle
const soucreCode = component.__sourceCode

动态加载bug

yarn build之后不能加载.md文件,浏览器提示404

原因是使用了动态加载,rollup不支持import()时拼字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const history = createWebHashHistory();
const md = filename => h(Markdown, {path: `../markdown/${filename}.md`, key: filename})
export const router = createRouter({
history, routes: [
{path: '/', component: Home},
{
path: '/doc', component: Doc, children: [
{path: '', redirect: '/doc/intro'},
{path: 'intro', component: md('intro')},
{path: 'install', component: md('install')},
{path: 'get-started', component: md('get-started')},
{path: 'switch', component: SwitchDemo},
{path: 'button', component: ButtonDemo},
{path: 'dialog', component: DialogDemo},
{path: 'tabs', component: TabsDemo},
]
},
]
});

调整过后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import intro from './markdown/intro.md'
import getStarted from './markdown/get-started.md'
import install from './markdown/install.md'

const history = createWebHashHistory();
const md = string => h(Markdown, {content: string, key: string})
export const router = createRouter({
history, routes: [
{path: '/', component: Home},
{
path: '/doc', component: Doc, children: [
{path: '', redirect: '/doc/intro'},
{path: 'intro', component: md(intro)},
{path: 'install', component: md(install)},
{path: 'get-started', component: md(getStarted)},
{path: 'switch', component: SwitchDemo},
{path: 'button', component: ButtonDemo},
{path: 'dialog', component: DialogDemo},
{path: 'tabs', component: TabsDemo},
]
},
]
});

发财UI 开发日志
https://bald3r.wang/2022/07/30/31-发财UI-开发日志1/
作者
Allen
发布于
2022年7月30日
许可协议