vue3实战技巧 - 组件的封装

news/2025/2/5 20:42:37/

目录

封装展示类组件

/src/examples/button.module.scss

/src/examples/button.scss

/src/examples/Components.tsx

封装容器类组件

封装输入组件


封装展示类组件

  • 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 Modulereturn <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.Elementreturn () => {return (<div><button>【child()】:{child()}</button><button>【&lt; Child /&gt;】:<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')}/><Input1value={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-modelvalue: anyonChange: (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>) // 类型转换}
}


http://www.ppmy.cn/news/435501.html

相关文章

Linux | 第一篇——常见指令汇总【超全、超详细讲解】

Linux之常见指令 &#x1f333;前言&#x1f4bb;操作系统的概念&#x1f4bb;Linux的使用环境介绍 &#x1f333;基本指令汇总一、【whoami】指令二、【pwd】指令三、【mkdir】指令四、【touch】指令五、【ls】指令1、拓展&#xff1a;文件的概念2、命令 - 命令选项 六、【cd】…

win10双显卡怎么切换amd和英特尔_amd双显卡怎么设置_win8切换amd双显卡的方法步骤...

2020-01-02 15:49:45 随着操作系统更新换代的快速发展,很多win8系统开始支持安装双显卡,但是有些软件或者游戏需要高性能的显卡,这个时候双显卡就需要进行切换,那么w8双显卡怎么切换?下面小编为大家带来w... 2015-10-27 14:06:29 根据部分用户的反映,在AMD和Intel双显卡的…

ibm笔记本一些使用技巧

1.高分屏游戏下全屏显示如何设置? 具体方法&#xff1a;在开始-程序-Access IBM-ThinkPad Configuration程序里选中右侧lcd在弹出来的对话框中general中的screen expansion 的下拉菜单选中的disable改成enable就可以了 2.电池 如何延长电池使用寿命 1.如果电池久未使用&#…

苹果Mac合上屏幕怎样才能不休眠?

MacBook 笔电最大的特色就是上盖打开即自动开机&#xff0c;合上屏幕则自动休眠。但如果今天想要在合上屏幕的情况下让电脑继续工作不进入睡眠模式&#xff0c;例如外接屏幕并继续操作、下载档案等等&#xff0c;该如何做到呢&#xff1f;今天就要告诉你两个App &#xff0c;即…

【转载】Linux/Unix笔记本

http://www.cnblogs.com/ggjucheng/archive/2012/08/18/2645321.html Linux介绍   Linux入门——个人感想   Google怎么用linux 初入Linux   Windows XP硬盘安装Ubuntu 12.04双系统图文详解   实例讲解虚拟机3种网络模式(桥接、nat、Host-only)   在线求助 man…

以计算机作为类 触摸板作为接口,给新手,笔记本电脑、接口、鼠标和触摸板的保养!...

原标题&#xff1a;给新手&#xff0c;笔记本电脑、接口、鼠标和触摸板的保养&#xff01; 保养所需工具 “ 清洁液(液晶清洁液就可以&#xff0c;成分是表面活性剂、氧化剂) 软布、海绵(类肤质地较软&#xff0c;布太硬或颗粒感太强擦拭时会划伤表面) 刷子(看情况使用 硬刷、软…

kali Linux显卡驱动安装(双显卡笔记本注意事项和解决方案)

kali Linux 显卡驱动安装及注意事项 一、禁用nouveau驱动这个我在上一篇博客里讲到&#xff0c;但是安装显卡还是必须做。&#xff08;如果做过了就直从二往后看。&#xff09; 打开终端在黑名单里添加mouveau驱动。&#xff1a;gedit /etc/modprobe.d/blacklist-libnfc.conf …

Linux/Unix笔记本

Linux介绍 Linux入门——个人感想 Google怎么用linux 初入Linux Windows XP硬盘安装Ubuntu 12.04双系统图文详解 实例讲解虚拟机3种网络模式(桥接、nat、Host-only) 在线求助 man page 文件,目录,权限 所有者,群组,其他人 文件的属性 Linux目录规范和含义 改变文件属性与权限 …