面向函数编程:关于函数式组件、dialog的api化

2022-10-29 16:45:30 浏览数 (2)

什么是函数式组件->Vue

  • 无状态
  • 无法实例化
  • 内部没有任何生命周期处理函数
  • 轻量,渲染性能高,适合只依赖于外部数据传递而变化的组件(展示组件,无逻辑和状态修改)
  • 在template标签里标明functional
  • 只接受props值
  • 不需要script标签 需要提供一个render方法, 接受一个参数(createElement函数), 方法内根据业务逻辑,通过createElement创建vnodes,最后return vnodes

createElement函数, 三个参数, 第一个参数是html标签或自定义组件,第二个参数一个obj(包含props, on...等等), 第三个参数children(通过createElement构建, 或者字符串)

官方文档

因为函数式组件没有状态,所以他们不需要像vue的响应式系统一样需要经过额外的初始化。 函数式组件仍然会对相应的变化做出响应式改变,比如新传入props,但是在组件本身中,它无法知道数据何时发生了更改,因为它不维护自己的状态。 对于大型应用程序,在使用函数式组件之后,你会看到Dom的渲染,更新会有重大改进

我们为什么要做dialog的api化这件事

dialog的api化等于是基于面向函数式编程的思维方式写代码,但是api化不等于实现函数式组件,这个一定要弄清楚!

首先是解决组件之前的依赖问题,组件间肯定是不能相互依赖的,因为不管是react还是vue,都应该遵循组件化的思想,那么在组件化思想中,非常重要的一点就是委托调用

  • 为什么要委托调用 即开发者A负责开发组件a,开发者B负责开发组件b,组件a与b之间在业务上构成父子关系,但是我们再设计组件的时候,需要把a,b设计成平行关系,即实现数据和业务的解绑和松耦合, 只有在这个前提下,我们才能够实现最小化组件和造轮子组汽车的目标。
  • 委托事件 即a组件与b组件通信时,开发者A不需要关注开发者B具体所实现的业务逻辑,两者间只要和前后端协同一样,约定好入参和回调, 开发者A委托开发者B开发组件b,并完成相应的业务后,通过callback回调事件回传开发者A,开发者A在callback中获取他想要 的response继续自己的业务开发。

弄清楚委托调用这一思想概念后,我们解决掉了组件的依赖问题,把两组件以松耦合的方式拆开,并且实施状态隔离。

那如何进行数据交互就是一个问题了;比如用户组件和其他组件,其他组件如何在不依赖用户组件的情况下获取到用户信息;

props传值

通过props传值进行组件间的数据交互

代码语言:javascript复制
showModal({
          prams:{ // param即传入组件的props,可传function、object、Nomal
            abc:this.abc,
            item:'xxxxxxxxxxxxs',
          },
          callback:(rsp)=>{
            console.log(rsp);
            if(rsp.ok) console.log('这是成功的回调')
          },
          onClose:(rsp)=>{
            console.log('关闭了弹窗')
          }
        })

实现原理

在document对象里,以body节点为父节点,创建一个div容器,modal弹窗动态渲染在该容器内,modal关闭的同时销毁div容器

代码语言:javascript复制
import Vue from 'vue';
import { uuid } from '../index';
export function showDialog(elementOrClass, props, isUnique = false, destroyDelay = 0) {

  //现在生成一个具备唯一表示id的divElement by Mothpro
  let dialogContainer = document.createElement('div');
  let id = elementOrClass.name
    ? elementOrClass.name
    : elementOrClass.type && elementOrClass.type.name   '_wrapper';

  if (!isUnique) {
    id  = '$'   uuid(8, 16);
  }
  // id = 'test';
  // let t = new Vue(document.getElementById(id));
  // t.$destroy();
  // console.log("----------------------------",t);
  // console.log(t.$delete);
  let removeNodeIfExist = (id) => {
    let domElement = document.getElementById(id);
    if (domElement) {
      //这个地方vue不需要销毁vNode节点,组件会自己销毁,勇辉告诉我的。。。。自动挡真牛逼!! by Mothrpro
      // ReactDom.unmountComponentAtNode(document.getElementById(id));
      domElement.parentNode.removeChild(domElement);

      //这里element-ui的dialog会建立一个叫做v-modal的蒙层,我要在关闭组件的同时销毁他 by Mothpro
      let vModals = document.getElementsByClassName('v-modal')[0];
      if(vModals) vModals.parentNode.removeChild(vModals);
    }
  };
  removeNodeIfExist(id);
  dialogContainer.id = id;
  function handleClose() {
    if (destroyDelay == 0) {
      removeNodeIfExist(id);
    } else {
      setTimeout(() => {
        removeNodeIfExist(id);
      }, destroyDelay);
    }
  }

  let handleClosePropName = 'onClose';
  document.body.appendChild(dialogContainer);
  let com = document.getElementById(id);

  dialogContainer = document.createElement('div');
  let elementId = id   '_';
  dialogContainer.id = elementId;
  com.append(dialogContainer);


  let element = undefined;
  if (typeof elementOrClass == 'function') {
    //FIXME 这是showMoadl传入Class的特殊情况,在我以前有遇到,目前项目里面还没遇到,我也懒得做处理了,但是这里是个坑,留个mark By Mothpro
    //如果是传入了类名 那用props实例化这个类

    // if (props.afterClose) {
    //   //这边请看上面的跟afterClose有关的章节
    //   element = React.createElement(elementOrClass, {
    //     ...props,
    //     afterClose: handleClose,
    //   });
    // } else {
    //   element = React.createElement(elementOrClass, {
    //     ...props,
    //     onClose: handleClose,
    //   });
    // }
  } else {
    //如果传入了一个react element 那就给这个element加上onClose属性并显示
    element = elementOrClass;
  }
  // props = element.props; //这个props可能是传进来的props 也可能是传进来的已经实例化的对象的props 反正就是props
  // UserOnClose=props.onClose; //这个UserOnClose一定是外面定义的onClose来负责关闭后刷新页面等操作

  // element.props[handleClosePropName] = handleClose;
  // console.log(handleClosePropName);
  // ReactDom.render(element, document.getElementById(id));


  new Vue({
    render: (h) => h(element,{
      props:{
        ...props,
        onClose:()=>{
          props.onClose();
          handleClose();
        },

      },
    })
  }).$mount(document.getElementById(elementId));
}

0 人点赞