2-3-7 Vue3 组件封装

展示类组件封装

当属性的绘制完全依赖属性时,封装变得非常容易:

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

你可能感兴趣的:(web,架构,elementui,vue.js,javascript)