目录
封装展示类组件
- Coding:纯展示类组件封装
- Coding:样式的处理
/src/examples/button.module.scss
.btn {
background-color: rgb(0, 119, 255);
}
.btn:hover {
background-color: rgb(0, 204, 255);
}
/src/examples/button.scss
.btn {
padding: 10px;
font-size: 18px;
border: none;
color: #fff;
}
.btn:hover {
color: #333;
}
/src/examples/Components.tsx
import { defineComponent, computed, ref, reactive, toRefs } from "vue";
import type { PropType, VNode, Ref } from 'vue'
// npm install scss 安装一下scss
import './button.scss'
import classes from "./button.module.scss" // 样式hash值全局不冲突classes.btn
export const Component01 = () => {
return <Button text={"Hello button!!"} />
}
// 封装展示类组件
const Button = defineComponent({
props: {
text: {
type: String
}
},
setup({ text }) {
return () => {
// 样式的处理
// CSS Module
return <button class={[classes.btn, "btn"]} style={{
border: "1px solid red",
}
}> {text}</button >
}
}
})
export const Component02 = () => {
// 样式的处理
return <Button2>
<span style={{ color: 'red', "font-size": '30px' }}>Hello button</span>
</Button2>
}
const Button2 = defineComponent({
setup(props, { slots }) {
const child = slots.default!
const Child = (slots.default!) as any as () => JSX.Element
return () => {
return (
<div>
<button>【child()】:{child()}</button>
<button>【< Child />】:<Child /></button>
</div>
)
}
}
})
export const Component03 = () => {
return <Panel header={
<span>header:Title</span>
}
v-slots={{
header: <span>slots.header:Title</span>
}}>
<span>Hello Content</span>
</Panel >
}
const Panel = defineComponent({
props: {
header: Object as PropType<JSX.Element>
},
setup(props, { slots }) {
return () => {
return (
<div>
<header>{props.header}</header>
<header>{slots.header!()}</header>
{slots.default!()}
</div>
)
}
}
})
封装容器类组件
- Coding:容器类组件封装
- Coding:Copy Props
import { defineComponent, computed, ref, reactive, toRefs } from "vue";
import type { PropType, VNode, Ref } from 'vue'
// 封装容器类组件
export const Component04 = () => {
return (
<Flex>
<div>
<div>a</div>
<div>b</div>
<div>c</div>
<div>d</div>
</div>
</Flex>
)
}
// 仅是举例,一般Flex不这样用,只有特别重要容器组件才会这样使用
const Flex = defineComponent({
setup(props, { slots }) {
return () => {
const vNode: VNode = slots.default!()[0] // 追求的是语义上的完美
if (!vNode.props) {
vNode.props = {}
}
vNode.props.style = {
display: 'flex'
}
console.log(vNode)
// <></>展示出来不占层级
return <>
{vNode}
</>
}
}
})
封装输入组件
- Coding:封装Input组件
追求的是语义上的完美
import { defineComponent, computed, ref, reactive, toRefs } from "vue";
import type { PropType, VNode, Ref } from 'vue'
// 封装输入类组件
export const Component05 = defineComponent({
setup() {
const form = reactive({
username: "abc"
})
setTimeout(() => {
form.username = "def"
}, 1000)
const { username } = toRefs(form)
return () => {
return (
<Input value={username} />
)
}
}
})
const Input = ({ value }: { value: Ref<string> }) => {
console.log('重绘:re render') // 非真实重绘,只是计算重绘,并没有渲染重绘
return <input value={value.value} onInput={e => {
value.value = (e.target as HTMLInputElement).value
}} />
}
export const Component06 = defineComponent({
setup() {
const { form } = useForm({ // 初始值,表单项
username: "abc",
password: '123456'
})
setTimeout(() => {
form.username = "def"
form.password = "jqkA123"
}, 1000)
return () => {
return (
<div>
<button onClick={() => {
console.log(form.getValues())
}}>submit</button>
<Input1
{...form.getField('username')}
/>
<Input1
value={form.password}
onChange={v => {
// 会冒泡,覆盖这里
form.password = v
}}
/>
</div>
)
}
}
})
const Input1 = ({
value,
onChange }: {
value: string,
onChange?: (v: string) => void
}) => { // value: Ref<string>过度包装
return <input value={value}
onChange={e => {
// 阻止一下这里冒泡
e.stopImmediatePropagation()
}}
onInput={e => {
onChange && onChange((e.target as HTMLInputElement).value)
}} />
}
// 表单类
class Form<T extends Record<string, any>> {
private data: {
[key: string]: any
}
constructor(data: T) {
this.data = reactive(data)
}
public getValue(key: string) {// ver 当前版本号
return this.data[key]
}
public setValue(key: string, value: any) {
this.data[key] = value
}
public getValues = () => {
// return unref(this.data)
return JSON.parse(JSON.stringify(this.data))
}
public getField = (key: string): { // === v-model
value: any
onChange: (v: any) => void
} => {
return {
value: this.data[key],
onChange: (v: any) => {
this.data[key] = v
}
}
}
}
// 接口
interface FormOperators<T> {
getValues(): T,
getField(key: string): { value: any, onChange: (v: any) => void }
}
// 表单函数 代理
function useForm<T extends Record<string, any>>(data: T) {
const form = new Form<T>(data)
const proxy = new Proxy(form, {
get(target, key) {
if (key === 'getValues') {
return form.getValues
} else if (key === 'getField') {
return form.getField
}
return form.getValue(key as string)
},
set(target, key, value) {
form.setValue(key as string, value)
return true
}
})
return {
form: proxy as any as (T & FormOperators<T>) // 类型转换
}
}