当属性的绘制完全依赖属性时,封装变得非常容易:
function Button({style, text} : {style : any, text : string}){
return
}
如果一个组件是容器,`vue` 是通过slot来处理的。
const ButtonWithSlots = (_ : any, context : any) => {
return
}
在`@vue/babel-plugin-jsx`中,slots被封装到了渲染函数的第二个参数中。 `slots.default` 代表了默认的`slot` 。使用时:
export const ButtonExample02 = () => {
return 你好!
}
当然可以有多个`slot` ,不过建议不要这样,因为这样阅读起来不是非常方便(美观):
const A = (props, { slots }) => (
<>
{ slots.default ? slots.default() : 'foo' }
{ slots.bar?.() }
>
);
const App = {
setup() {
const slots = {
bar: () => B,
};
return () => (
A
);
},
};
// or
const App = {
setup() {
const slots = {
default: () => A,
bar: () => B,
};
return () => ;
},
};
// or you can use object slots when `enableObjectSlots` is not false.
const App = {
setup() {
return () => (
<>
{{
default: () => A,
bar: () => B,
}}
{() => "foo"}
>
);
},
};
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(null)
watch(
() => props.value,
() => {
const ipt = input.value!
if(ipt.value !== props.value) {
ipt.value = props.value || ""
}
}
)
return () => {
return (
{
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
formData.username = v}
/>
formData.info = v}
/>
}
}
})
可以对表单数据进行一定的封装,使用起来更加方便:
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 () => (
)
},
})
封装事件和计算
function useMouse() {
const x = ref(0)
const y = ref(0)
function handler(e: MouseEvent) {
x.value = e.x
y.value = e.y
console.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 = 0
private top: number = 0
private scrollHeight: number = 0
private offsetHeight: number = 0
private 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 = left
this.top = top
this.scrollHeight = scrollHeight
this.offsetHeight = offsetHeight
if (this.bottomReached()) {
this.triggerScrollToBottom()
}
}
public bottomReached() {
return this.top + this.offsetHeight >= this.scrollHeight
}
}
const useScroll = () => {
const scrollInfo = new ScrollDescriptor()
const scrollHandler = (
e: Event
) => {
const scroller = e.currentTarget as T
const left = scroller.scrollLeft
const top = scroller.scrollTop
scrollInfo.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 () => (
)
},
})
封装请求和逻辑
import {ref, defineComponent} from 'vue'
import Mock from 'mockjs'
type Product = {
name : string
}
function useProducts() {
const list = ref(null)
async function request() {
list.value = Mock.mock({
"array|1-10" : [{
name: /iphone|xiaomi|hongmi|huawei|sanxing|google|ms/,
}],
}).array
console.log(list.value)
}
request()
return {
list,
reload: request,
}
}
export const ProductList = defineComponent({
setup() {
const {list, reload} = useProducts()
return () => {
return
{list.value?.map( (x, i) => {
return - {x.name}
})}
}
}
})
1