什么是函数式组件->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));
}