2-3-7 Vue3 组件封装
展示类组件封装
当属性的绘制完全依赖属性时,封装变得非常容易:
function Button({style, text} : {style : any, text : string}){return <button style={style}>text</button>
}
容器类组件
如果一个组件是容器,`vue` 是通过slot来处理的。
const ButtonWithSlots = (_ : any, context : any) => {return <button>{context.slots.default()}</button>
}
在`@vue/babel-plugin-jsx`中,slots被封装到了渲染函数的第二个参数中。 `slots.default` 代表了默认的`slot` 。使用时:
export const ButtonExample02 = () => {return <ButtonWithSlots><span>你好!</span></ButtonWithSlots>
}
当然可以有多个`slot` ,不过建议不要这样,因为这样阅读起来不是非常方便(美观):
const A = (props, { slots }) => (<><h1>{ slots.default ? slots.default() : 'foo' }</h1><h2>{ slots.bar?.() }</h2></>
);const App = {setup() {const slots = {bar: () => <span>B</span>,};return () => (<A v-slots={slots}><div>A</div></A>);},
};// orconst App = {setup() {const slots = {default: () => <div>A</div>,bar: () => <span>B</span>,};return () => <A v-slots={slots} />;},
};// or you can use object slots when `enableObjectSlots` is not false.
const App = {setup() {return () => (<><A>{{default: () => <div>A</div>,bar: () => <span>B</span>,}}</A><B>{() => "foo"}</B></>);},
};
输入组件
vue Input表单的一个完整的例子
import { ref, defineComponent, PropType, watch } from "vue"const Input = defineComponent({props: {onChange: {type: Function as PropType<(v: any) => void>,required: false,},value: {type: String,required: false,},},setup(props) {const input = ref<HTMLInputElement | null>(null)watch(() => props.value,() => {const ipt = input.value!if(ipt.value !== props.value) {ipt.value = props.value || ""}})return () => {return (<input onInput={e => {props.onChange &&props.onChange((e.target as HTMLInputElement).value)}} value={props.value} ref={input} />)}},
})export const FormExample = defineComponent({setup(){let formData = {username : '张三',info : "xxx"}const ver = ref(0)return () => {return <div key={ver.value}><button onClick={() => {console.log(formData)formData = {username : '张三',info : "xxx"}ver.value ++}}>重置/提交</button><Inputvalue={formData.username}onChange={(v) => formData.username = v}/><Inputvalue={formData.info}onChange={(v) => formData.info = v}/></div>}}})
对表单数据的封装
可以对表单数据进行一定的封装,使用起来更加方便:
import {ref,defineComponent,PropType,watch,
} from "vue"import {Input} from '../components/Input'
import {useForm} from '../hooks/useForm'export const FromExample02 = defineComponent({setup() {const {form, ver} = useForm({username: "张三",info: "xxx",})watch(form.getValues(), () => {console.log('form data changed', form.getValues().value)})return () => (<div><buttononClick={() => {const values = form.getValues().valueconsole.log("submit", values)form.setValues({username: "张三",info: "xxx",})ver.value++}}>提交/重置</button><Input{...form.username}/><Input{...form.info}/></div>)},
})
封装公共行为
封装事件和计算
function useMouse() {const x = ref(0)const y = ref(0)function handler(e: MouseEvent) {x.value = e.xy.value = e.yconsole.log('move', e.x, e.y)}window.addEventListener("mousemove", handler)onScopeDispose(() => {window.removeEventListener("mousemove", handler)})return { x, y }
}
公共Scroll事件的封装
封装一个滚动到底部的判定
import { defineComponent } from "vue"class ScrollDescriptor {private left: number = 0private top: number = 0private scrollHeight: number = 0private offsetHeight: number = 0private scrollToBottomHandlers: Function[] = []public onScrollToBottom(handler: Function) {this.scrollToBottomHandlers.push(handler)return () => {this.scrollToBottomHandlers =this.scrollToBottomHandlers.filter((x) => x !== handler)}}private triggerScrollToBottom() {this.scrollToBottomHandlers.forEach((h) => h())}public update(left: number,top: number,offsetHeight: number,scrollHeight: number) {this.left = leftthis.top = topthis.scrollHeight = scrollHeightthis.offsetHeight = offsetHeightif (this.bottomReached()) {this.triggerScrollToBottom()}}public bottomReached() {return this.top + this.offsetHeight >= this.scrollHeight}
}const useScroll = () => {const scrollInfo = new ScrollDescriptor()const scrollHandler = <T extends HTMLElement>(e: Event) => {const scroller = e.currentTarget as Tconst left = scroller.scrollLeftconst top = scroller.scrollTopscrollInfo.update(left,top,scroller.offsetHeight,scroller.scrollHeight)}return {onScroll: scrollHandler,info: scrollInfo,}
}export const ScrollerExample = defineComponent({setup() {const { onScroll, info } = useScroll()info.onScrollToBottom(() => {console.log('here---')})return () => (<divonScroll={onScroll}style={{height: '600px',width: '400px',overflow: "scroll",}}><divstyle={{height: '800px',width: "100%",background: "red",}}></div><divstyle={{height: '800px',width: "100%",background: "blue",}}></div><divstyle={{height: '800px',width: "100%",background: "yellow",}}></div></div>)},
})
封装请求和逻辑
import {ref, defineComponent} from 'vue'
import Mock from 'mockjs'type Product = {name : string
}
function useProducts() {const list = ref<Product[] | null>(null)async function request() {list.value = Mock.mock({"array|1-10" : [{name: /iphone|xiaomi|hongmi|huawei|sanxing|google|ms/,}],}).arrayconsole.log(list.value)}request()return {list,reload: request,}
}export const ProductList = defineComponent({setup() {const {list, reload} = useProducts()return () => {return <div><button onClick={reload}>reload</button><ul>{list.value?.map( (x, i) => {return <li key={i}>{x.name}</li>})}</ul></div>}}})
1
2-3-7 Vue3 组件封装相关推荐
- element-plus的el-icon和@element-plus/icons vue3 组件封装与使用
使用 element-plus 时发现了一个问题:icon 需要单独安装和引入,让我很是难受,官网是这么说的(大概意思如下): $ yarn add @element-plus/icons # 或者 ...
- 【vue3组件封装】Icon图标组件
使用 <s-icon icon="icon-file"/> 准备图标 这里使用的icon均自于https://www.iconfont.cn/,它是支持unicode. ...
- vue3 - 仿 element-ui Breadcrumb 面包屑组件封装自己的面包屑组件
仿 element-ui Breadcrumb 面包屑组件封装自己的面包屑组件 element-ui 面包屑结构 <el-breadcrumb separator="/"&g ...
- Vue3 element-ui实现Pagination分页组件--封装分页
什么是Pagination分页组件? 在 B 端的 web 开发中,分页组件或者叫分页器,是较为常用的控件之一,通常配合表格或列表,实现数据量大的情况下,分页拆解数据的功能. 1.scrollTo和滚 ...
- vue3使用jodit富文本编辑器,自定义各项配置及组件封装
目录 常用配置 设置中文 字体设置 CDN的引用 图片上传 对编辑器中生成的元素添加默认属性 组件封装 本文使用时的版本: "vue": "^3.2.36", ...
- vue2+webpack/vue3+vite 封装svg组件总结笔记
一.vue2+webpack 1.npm安装依赖包 npm i svg-sprite-loader package.json "svg-sprite-loader": " ...
- vue3中,echarts使用(四)02——柱状图之堆叠条形图-定制化 封装切换tag标签组件 封装title组件
vue3中,echarts使用(四)02--柱状图之堆叠条形图-定制化 & 封装切换tag标签组件 & 封装title组件 效果 代码 1.主页面 index.vue <temp ...
- Vue3VideoPlay+vue3+ts封装一个视频播放组件
vue3+ts封装一个视频播放组件 基于Vue3VideoPlay 做了常用的配置,复制即用! 官方文档https://codelife.cc/vue3-video-play/ 安装 npm安装: n ...
- 2.vue3医疗在线问诊项目 - _登录模块 ==> 代码片段、css变量主题定制、cp-nav-bar组件封装、svg打包精灵图插件、cp-icon组件封装、表单校验、密码登录、短信验证码登录及两者
2.医疗在线问诊项目 - _登录模块 ==> 代码片段.css变量主题定制.cp-nav-bar组件封装.svg打包精灵图插件.cp-icon组件封装.表单校验.密码登录.短信验证码登录及两者的 ...
最新文章
- ubuntu在系统启动logo过后无法进入桌面的处理方法
- CF572_Div2_D2
- VS2008如何添加 OLE/COM 对象查看器 .
- vue检测不到data里数组里面元素的变化
- 前后端分离架构一直没机会实战?1周完成Vue+Core WebApi移动商城实战(含源码)!...
- Uva 11178 Morley定理
- ftp上传乱码_ftp同步图片到本地文件夹,ftp同步图片到本地文件夹的实现步骤
- 智慧机场大数据可视化分析决策系统
- BUUCTF刷题-RAR 压缩包暴力破解密码
- 职场泥潭 | 这样的IT公司绝对不宜久留
- Genesys Business Continuity 部署
- MySQL 常见的 9 种优化方法
- Android Studio出现APP闪退问题(My Application keeps stopping)
- 鼠标每隔几秒失去焦点,鼠标每隔几秒转圈,鼠标每隔几秒刷新
- dxc 5.0 多线程同步
- 选定关键词爬取智联招聘职位概览信息
- 秋招春招,网申在线测评中的智力测试
- 【功能安全】【AutoSAR】程序流监控机制
- 自己动手修改用友致远OA2.75的问题
- 女生应该找一个会打DOTA有会玩ACM的男生当老公