前言随着vue3.0beta的发布,其核心插件vuex、vue-router也发布了beta和alpha版本进行适配。感觉差不多可以用3.0开始一个项目提前感受一下CompositionAPI的魅力了。事实证明,没有任何ui框架发布任何beta或alpha来适应3.0。因此,尝试使用一个简单的ui插件来查看与2.0的区别。所以这个项目就是重构element-ui。目标,Adapt3.0。当然,本文主要讲解插件开发的不同点。install功能插件的入口文件index.jsconstinstall=function(app,opts={}){//locale.use(opts.locale);//locale.i18n(opts.i18n);//注册组件components.forEach(component=>{//调试器app.component(component.name,component)})//Vue.use(InfiniteScroll);//Vue.use(Loading.directive);/****Vue.prototype.$ELEMENT={大小:opts.size||'',zIndex:opts.zIndex||2000};*/app.provide(ELEMENTSymbol,{size:opts.size||'',zIndex:opts.zIndex||2000})//Vue.prototype.$loading=Loading.service;//Vue.prototype.$msgbox=MessageBox;//Vue.prototype.$alert=MessageBox.alert;//Vue.prototype.$confirm=MessageBox.confirm;//Vue.prototype.$prompt=MessageBox.prompt;//Vue.prototype.$notify=通知;//Vue.prototype.$message=Message;}这是element-ui源码install函数的改造。最大的区别是install函数的参数从原来的vue变成了app。这不仅仅是一个名字的改变。最初的Vue是一个原型,可以理解为一个类。现在应用程序是Vue的一个实例。这样一来,用法就完全不同了。不能再像以前那样使用原型的prototype属性来实现全局变量、函数等。并且新的API不再推荐使用this.$xxx来访问全局对象。而是使用provide和inject函数进行封装。因此,在上面的代码中,所有的原型都必须被注释掉。也正是因为这个原因,一些开发者在vue3.0中直接导入当前element-ui版本,运行时直接报错。其实卡在这里是因为缺少prototype属性。虽然button.vue重构整个element-ui是一个漫长的踩坑之旅,但是柿子还是要先捡起来,先做一个比较简单的按钮组件。exportdefault{name:'ElButton',props:{type:{type:String,default:'default'},size:String,icon:{type:String,default:''},nativeType:{type:String,default:'button'},loading:Boolean,disabled:Boolean,plain:Boolean,autofocus:Boolean,round:Boolean,circle:Boolean},setup(props,ctx){//注入constelForm=inject('elForm','')constelFormItem=inject('elFormItem','')constELEMENT=useELEMENT()//computedconst_elFormItemSize=computed(()=>{return(elFormItem||{}).elFormItemSize})constbuttonSize=computed(()=>{returnprops.size||_elFormItemSize.value||(ELEMENT||{}).size})constbuttonDisabled=computed(()=>{returnprops.disabled||(elForm||{}).disabled})console.log(buttonSize.value)//methodsconsthandleClick=(evt)=>{ctx.emit('click',evt)}return{buttonSize,buttonDisabled,handleClick}},/*inject:{elForm:{default:''},elFormItem:{default:''}},*//*computed:{_elFormItemSize(){return(this.elFormItem||{}).elFormItemSize;},buttonSize(){返回this.size||这个._elFormItemSize||(this.$ELEMENT||{}).size;},buttonDisabled(){返回this.disabled||(this.elForm||{}).disabled;}},*//*方法:{handleClick(evt){this.$emit('click',evt);}}*/};模板部分没有改动(可能有些改动我不知道),所以直接copy源码就不贴了。js部分,最大的不同是新API推荐的新函数setup(),几乎是一个allinone的函数,可以把之前的data,computed,methods等都写进去。写的好,一个组件就完成了name、props、setup三个属性。setup中的props参数用于获取props中的属性值。ctx参数是一个代理对象,封装了slots、emit等对象,用于替代之前的this.$slots、this.$emit等按钮组件,比较简单。三个计算属性被计算函数替换。注意计算函数返回的是一个Ref对象,在setup中访问时需要写成xxx.value来获取值。在模板中,不需要添加值。会被自动解析。旧的methods属性中的函数直接定义在setup函数中,可以通过return返回。row.js是一个没有模板的纯js组件。选择这个组件,看看它的render函数在新的API中应该怎么写。import{computed,h,provide,inject}from'vue'//常量constgutterSymbol=Symbol()exportfunctionuseGutter(){returninject(gutterSymbol)}exportdefault{name:'ElRow',componentName:'ElRow',props:{tag:{type:String,default:'div'},gutter:Number,type:String,justify:{type:String,default:'start'},align:{type:String,默认:'top'}},setup(props,ctx){conststyle=()=>computed(()=>{constret={}if(props.gutter){ret.marginLeft=`-${props.gutter/2}px`ret.marginRight=ret.marginLeft}returnret})provide(gutterSymbol,props.gutter)return()=>h(props.tag,{class:['el-row',props.justify!=='开始'?`is-justify-${props.justify}`:'',props.align!=='top'?`is-align-${props.align}`:'',{'el-row--flex':props.type==='flex'}],样式},ctx.slots);},/*计算:{style(){constret={};如果(this.gutter){ret.marginLeft=`-${this.gutter/2}px`;退役。marginRight=ret.marginLeft;返回ret;}},*//*render(){returnh(this.tag,{class:['el-row',this.justify!=='start'?`is-justify-${this.justify}`:'',this.align!=='top'?`is-align-${this.align}`:'',{'el-row--flex':this.type==='flex'}],样式:this.style},this.$slots.default);}*/}在新的API中,使用template时通过setup的return集成了render函数,return是模板中需要使用的绑定数据对象。但是如果没有模板,返回的就是渲染函数。同样,这个返回也支持jsx语法。比如return()=>
