types组件types能用于节点类型的判断和节点的生成,但是主要还是用来节点的生成,因为节点类型的判断可以不用该组件,也能实现类型判断//其他类型也是一样type.isIdentifier(path.node)//相当于path.node.type==='Identifier'type.isIdentifier(path.node,{'name':'x'})//相当于path.node.type==='Identifier'&&path.node.name==='x'节点生成生成实例代码constfs=require('fs')consttype=require("@babel/types")constgenerator=require("@babel/generator").default//AST转换为代码letobjPro1=type.objectProperty(key=type.identifier(name="name"),//第一个属性value=type.stringLiteral(value="haha"))//第一个属性值letbojPro2=type.objectProperty(key=type.identifier(name="add"),value=type.functionExpression(//函数节点id=null,params=[type.identifier(name="a"),type.identifier(name="b")],//参数列表body=type.blockStatement(//函数体body=[type.returnStatement(//返回值argument=type.binaryExpression(//二项式operator="+",left=type.binaryExpression(operator="+",left=type.identifier(name="a"),right=type.identifier(name="b")),right=type.numericLiteral(value=1000)))])))letbojPro3=type.objectProperty(key=type.identifier(name="mul"),//第三个属性value=type.functionExpression(//第三个属性值id=null,params=[type.identifier(name="a"),type.identifier(name="b")],body=type.blockStatement(body=[type.returnStatement(argument=type.binaryExpression(operator="+",left=type.binaryExpression(operator="*",left=type.identifier(name="a"),right=type.identifier(name="b")),right=type.numericLiteral(value=1000)))])))letobj=type.objectExpression([objPro1,bojPro2,bojPro3])//变量初始化letletDec=type.variableDeclarator(type.identifier(name="obj"),init=obj)//变量名letlocalAst=type.variableDeclaration("let",[letDec])//声明变量//ast转化为代码letcode=generator(localAst).codefs.writeFile("./output/code.js",code,(err=>{}))上面使用到stringLiteral、numericLiteraltypes还提供了其他字面量,按照语法树来,都是差不多的declarefunctionstringLiteral(value:string):StringLiteral;declarefunctionnumericLiteral(value:number):NumericLiteral;declarefunctionnullLiteral():NullLiteral;declarefunctionbooleanLiteral(value:boolean):BooleanLiteral;declarefunctionregExpLiteral(pattern:string,flags?:string):RegExpLiteral;当界面量太多,太复杂的时候,Bable也提供了一个简便的方式valueToNode()//可以看出valueToNode可以很方便的生成其他类型exportfunctionvalueToNode(value:undefined):IdentifierexportfunctionvalueToNode(value:boolean):BooleanLiteralexportfunctionvalueToNode(value:null):NullLiteralexportfunctionvalueToNode(value:string):StringLiteralexportfunctionvalueToNode(value:number):NumericLiteral|BinaryExpression|UnaryExpressionexportfunctionvalueToNode(value:RegExp):RegExpLiteralexportfunctionvalueToNode(value:ReadonlyArray<undefined|boolean|null|string|number|RegExp|object>):ArrayExpressionexportfunctionvalueToNode(value:object):ObjectExpressionexportfunctionvalueToNode(value:undefined|boolean|null|string|number|RegExp|object):Expressionconsole.log(generator(type.valueToNode(123)).code)console.log(generator(type.valueToNode('mimi')).code)console.log(generator(type.valueToNode(undefined)).code)console.log(generator(type.valueToNode(null)).code)/*123"mimi"undefinednull*/
parse&generator组件parse作用是代码转化为AST结构解析网站:https://astexplorer.net/constparser=require("@babel/parser");//需要导入letast=parser.parse(js_code)//代码转化为ast结构,与网站上一样letast1=parser.parse(js_code,{sourceType:"module",//如果有importexport关键字,需要使用该参数})console.log(JSON.stringify(ast,null,2))generator作用是AST结构转化为代码letcode=generator(ast).codeletcode1=generator(ast,{retainLines:false,//默认false,是否输出与源代码相同的行号comments:false,//默认true,是否保留注释compact:true//默认false,是否压缩代码}).codetraverse&visitor组件traverse用来遍历AST结构的节点,简单点说就是把所有节点都运行一遍traverse使用的深度优先策略//导入consttraverse=require("@babel/traverse").default;//遍历节点constgenerator=require("@babel/generator").default//AST转换为代码//相关操作letvisitor={}visitor.FunctionExpression=function(path){console.log("mmmmm")}traverse(ast,visitor)/*源码有两个函数节点所以输出两次mmmmmmmm*/visitor三种写法按照自己的喜好选择,最常用的visitor2letvisitor1={FunctionExpression:function(path){console.log('...')}}letvisitor2={FunctionExpression(path){console.log('...')}}letvisitor3={FunctionExpression:{enter(path){console.log('进入->函数节点')},exit(path){console.log('退出<-函数节点')}}}traverse(ast,visitor3)visitor组合写法使用|组合不同的类型letvisitor1={'FunctionExpression|BinaryExpression':function(path){console.log('...')}}letvisitor2={'FunctionExpression|BinaryExpression'(path){console.log('...')}}letvisitor3={'FunctionExpression|BinaryExpression':{enter(path){console.log('进入->节点')},exit(path){console.log('退出<-节点')}}}traverse(ast,visitor3)使用多个函数处理节点,会按照函数顺序执行functionfun1(path){console.log('11')}functionfun2(path){console.log('22')}letvisitor={FunctionExpression:{enter:[fun1,fun2]}}traverse(ast,visitor)traverse并非必须从头遍历//修改函数第一个参数为x,并修改函数内所有用了该参数的地方constupdateParamNameVisitor={Identifier(path){if(path.node.name===this.paramName){path.node.name="x"}}}constvisitor={FunctionExpression(path){//遍历函数节点constparamName=path.node.params[0].name//内部循环path.traverse(updateParamNameVisitor,{paramName//向子循环传递参数})}}traverse(ast,visitor)
依赖安装npminstall--save-dev@babel/core@babel/cli@babel/preset-envnpminstall--save@babel/polyfill结构操作思想:读取代码转换为AST->对节点进行增删改查操作->保存结果constfs=require('fs');constparser=require("@babel/parser");//代码解析为ASTconsttraverse=require("@babel/traverse").default;//遍历节点consttype=require("@babel/types")//节点类型判断constgenerator=require("@babel/generator").default//AST转换为代码constjs_code=fs.readFileSync("./input",{encoding:"utf-8"})letast=parser.parse(js_code)//代码转化为ast//相关操作//ast转化为代码letcode=generator(ast).code//保存fs.writeFile("./output",code,(err=>{}))案例代码letobj={name:'haha',add:function(a,b){returna+b+1000},mul:function(a,b){returna*b+1000}}
组件内的守卫组件内的守卫又叫路由钩子,可以理解为页面跳转的中间件处理函数官方文档:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E7%BB%84%E4%BB%B6%E5%86%85%E7%9A%84%E5%AE%88%E5%8D%AB可用的API提供有三个API,这三个API的参数是一样的(to,from,next)=>{...}xx(to,from,next)=>{//to将要跳转到的页面对象//from跳转前的页面对象//next()不填参数表现继续跳转d到下一个页面//next('/path')改变跳转的路由//next(false)返回原来的界面}beforeRouteEnter进入路由时<template></template><script>exportdefault{name:'User',beforeRouteEnter:(to,from,next)=>{console.log("进入页面");next();}}</script><style></style>beforeRouteLeave离开路由时<template></template><script>exportdefault{name:'User',beforeRouteEnter:(to,from,next)=>{console.log("离开页面");next();}}</script><style></style>beforeRouteUpdate路由改变<template></template><script>exportdefault{name:'User',beforeRouteEnter:(to,from,next)=>{console.log("路由改变,组件重用时");next();}}</script><style></style>
说明思想:用Miniconda管理多个Python版本,在使用poetry创建虚拟环境的时候,指定Miniconda环境里的Py版本使用前的准备安装Miniconda链接:https://docs.conda.io/en/latest/miniconda.html安装poetry链接:https://bigdataboy.cn/post-399.html创建环境使用Miniconda创建多个Py版本的环境创建不同Python版本的虚拟环境condacreate-nPy3.9python=3.9查看环境condaenvlist使用第一步初始化poetry,使用命令:poetryinit,如果不是新项目直接跳到第二步这里有个坑,poetry指定Py版本的时候,只好写成这种格式~3.8(支持3.8.<3.9.0),不然会报版本不一致的错误,原因就是conda下载的版本是3.8.x,两处版本支持范围要严格一直F:\Tools\pyCode\test>poetryinitThiscommandwillguideyouthroughcreatingyourpyproject.tomlconfig.Packagename[test]:Version[0.1.0]:Description[]:Author[‘zbigdataboy‘<876545500@qq.com>,ntoskip]:bigdataboyLicense[]:CompatiblePythonversions[^3.9]:~3.8Wouldyouliketodefineyourmaindependenciesinteractively?(yes/no)[yes]noWouldyouliketodefineyourdevelopmentdependenciesinteractively?(yes/no)[yes]noGeneratedfile[tool.poetry]name="test"version="0.1.0"description=""authors=["bigdataboy"][tool.poetry.dependencies]python="~3.8"[tool.poetry.dev-dependencies][build-system]requires=["poetry-core>=1.0.0"]build-backend="poetry.core.masonry.api"Doyouconfirmgeneration?(yes/no)[yes]yes第二步peotry使用指定的解释器如果报版本不一致的错误,看第一步的坑poetryenvuseD:\ProgramData\miniconda3\envs\Py3.8\python.exe第三步安装相关依赖poetryinstall
介绍VueRouter是Vue.js的官方路由。它与Vue.js核心深度集成,让用Vue.js构建单页应用变得轻而易举。功能包括:嵌套路由映射动态路由选择模块化、基于组件的路由配置路由参数、查询、通配符展示由Vue.js的过渡系统提供的过渡效果细致的导航控制自动激活CSS类的链接HTML5history模式或hash模式可定制的滚动行为URL的正确编码官网文档:https://router.vuejs.org/zh/introduction.html安装vue-router:npminstallvue-router//默认安装最新稳定版npminstallvue-router@3//安装3.Xvue-routervue2.X使用一个重要概念Vue的是单页程序,路由跳转是把内容展示在<router-view>标签上也能实现页面的条件创建路由管理文件在src里新建router文件夹,在新建index.js//src/router/index.jsimportVuefrom"vue";importVueRouterfrom"vue-router";importLoginfrom'../components/Login'importRegisterfrom'../components/Register'Vue.use(VueRouter)//使用VueRouterexportdefaultnewVueRouter({//导出VueRouter实例routes:[{//登录path:'/login',//请求路径name:'login',//定义名字为了更好的传递参数component:Login,//展示的组件},{//注册path:'/register',name:'register',component:Register,}]})在src/main.js引入路由importVuefrom'vue';importrouterfrom'./router';//自动扫描index.js文件importAppfrom'./App';newVue({el:'#app',router,//添加render:h=>h(App)});路由跳转<router-link>最终会被渲染成<a>标签<router-linkto="/register"><h2>注册</h2></router-link><router-linkto="/login"><h3>登录</h3></router-link><!--路由匹配到的组件将渲染在这里--><router-view></router-view><!--路由定义了名字才能这样传递参数--><router-link:to="{name:'user',params:{userId:123}}">User</router-link>路由模式两种路由方式都不会重新加载页面hash路由模式(默认值):http://localhost:8080/#/registerhistory路由模式:http://localhost:8080/registerexportdefaultnewVueRouter({mode:'history',routes:[...]})路由传参路由参数的传递,设置后,在$route.params获取参数值exportdefaultnewVueRouter({routes:[//动态路径参数以冒号开头{path:'/user/:id',component:User},//设置多段路径参数{path:'/user/:username/post/:id',component:User}]})/*/user/12-->$route.params-->{id:12}/user/Bob/post/2-->$route.params-->{username:'Bob',id:2}*/使用$route.params会造成严重耦合,所有还有一种方式传递路由参数exportdefaultnewVueRouter({mode:'history',routes:[{path:'/user/:id',name:'user',component:User,props:true,//设置props为ture}]})捕获所有路由或404Notfound路由路由是支持正则表达式匹配的,匹配的优先级就是定义路由的顺序当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由{path:'*'}通常用于客户端404错误。如exportdefaultnewVueRouter({routes:[//动态路径参数以冒号开头{path:'/user/:id',component:User},//设置多段路径参数{path:'/user/:username/post/:id',component:User},{//通配会匹配所有路径path:'*'},{//会匹配以`/user-`开头的任意路径path:'/user-*'}]})重定向exportdefaultnewVueRouter({routes:[{path:'/a',redirect:'/b'},//直接重定向{path:'/c',redirect:{name:'login'}}//可以使用name]})嵌套路由效果其实是在子组件中渲染界面exportdefaultnewVueRouter({routes:[//动态路径参数以冒号开头{path:'/user/:id',component:User,children:[{//当/user/:id/profile匹配成功,//UserProfile会被渲染在User的<router-view>中path:'profile',component:UserProfile},{//当/user/:id/posts匹配成功//UserPosts会被渲染在User的<router-view>中path:'posts',component:UserPosts}]},})
ElementUI说明ElementUI是饿了么团队基于Vue开发的前端框架,使用方便简单官方文档:https://element.eleme.cn/#/zh-CN/component推荐使用npm的方式安装,它能更好地和webpack打包工具配合使用。npmielement-ui-S引入Element操作main.js完整引入打包体积会变的大一点importVuefrom'vue';importElementUIfrom'element-ui';import'element-ui/lib/theme-chalk/index.css';importAppfrom'./App.vue';Vue.use(ElementUI);#使用ElementUInewVue({el:'#app',render:h=>h(App)});按照需要引入借助babel-plugin-component我们可以只引入需要的组件,以达到减小项目体积的目的。npminstallbabel-plugin-component-D修改.babelrc文件{"presets":[["es2015",{"modules":false}]],"plugins":[["component",{"libraryName":"element-ui","styleLibraryName":"theme-chalk"}]]}接下来就能安装需要引入组件importVuefrom'vue';import{Button,Select}from'element-ui';importAppfrom'./App.vue';Vue.component(Button.name,Button);Vue.component(Select.name,Select);/*或写为*Vue.use(Button)*Vue.use(Select)*/newVue({el:'#app',render:h=>h(App)});官网有个完整单独组件引入https://element.eleme.cn/#/zh-CN/component/quickstart现在基于Element的环境开发搭建完毕
安装安装Vue//npminstall-gvue-g全局安装npminstall-gvue安装Vue-cli安装之后,你就可以在命令行中使用vue命令。npminstall-g@vue/cli//npmupdate-g@vue/cli全局升级npminstall-g@vue/cli-init//使用vue-cli相关模板创建项目这里使用webpackvue-V//查看版本创建一个项目运行下面命令,使用Vue-cli创建webpack模板项目vueinitwebpackhello_worldD:\HBuilderProjects>vueinitwebpackhello_world?Projectnamehello_world#项目名称?ProjectdescriptionAVue.jsproject#项目描述?Authorbigdataboy#项目作者?Vuebuild(Usearrowkeys)>Runtime+Compiler:recommendedformostusersRuntime-only:about6KBlightermin+gzip,buttemplates(oranyVue-specificHTML)areONLYallowedin.vuefiles-renderfunctionsarerequiredelsewhere然后四个No,选择npm安装依赖,等待下载Installvue-router?No#路由不安装?UseESLinttolintyourcode?No#代码检测不安装?SetupunittestsNo#测试不安装?Setupe2etestswithNightwatch?No#调试不安装?Shouldwerun`npminstall`foryouaftertheprojecthasbeencreated?(recommended)npm运行ui界面创建web-ui界面不止能创建项目,还能管理项目,依赖,插件,配置打包等vueui手动选择全部都不选选择Vue2目录介绍启动&打包npmrundev//开发环境打包,主要用于测试,不会生成打包文件npmrunstart//与上一个相同,最终调用的还是上一个命令npmrunbuild//打包
说明插槽:可以理解为占一块位置,然后可以插入组件,当有数据传入待插入组件时,再展示出来,没有数据时,插槽位置为空有数据时没有数时注册组件//留有插槽的组件模板里关联有待插入组件Vue.component('item',{template:'<div>\<slotname="h4-title"></slot>\<ul>\<slotname="li-slot"></slot>\</ul>\</div>'})//待插入组件Vue.component('h4-title',{props:['title'],template:'<h4>{{title}}</h4>'})//待插入组件Vue.component('li-slot',{props:['item'],template:'<li>{{item}}</li>'})使用item组件<item><!--插槽与待插入组件关联--><h4-titleslot="h4-title":title="title"></h4-title><li-slotslot="li-slot"v-for="(item,index)initems":item='item'></li-slot></item>全部代码<!DOCTYPEhtml><html><head><metacharset="utf-8"/><title></title><!--<scriptsrc="https://unpkg.com/vue@next"></script>--><scriptsrc="js/v2.6.10/vue.min.js"type="text/javascript"charset="utf-8"></script></head><body><divid="app"><item><!--插槽与待插入组件关联--><h4-titleslot="h4-title":title="title"></h4-title><li-slotslot="li-slot"v-for="(item,index)initems":item='item'></li-slot></item></div><script>Vue.component('item',{template:'<div>\<slotname="h4-title"></slot>\<ul>\<slotname="li-slot"></slot>\</ul>\</div>'})Vue.component('h4-title',{props:['title'],template:'<h4>{{title}}</h4>'})Vue.component('li-slot',{props:['item'],template:'<li>{{item}}</li>'})varvue=newVue({el:'#app',data:{counter:'hello',title:'标题',items:['AA','BB','CC']}})</script></body></html>
内置对象JavaScript中有很多内置对象,它们可以直接在TypeScript中当做定义好了的类型。内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指ECMAScript和其他环境(比如DOM)的标准。ECMAScript的内置对象Boolean、Number、String、Date、RegExp、Errorletb:Boolean=newBoolean(1)letn:Number=newNumber(true)lets:String=newString('abc')letd:Date=newDate()letr:RegExp=/^1/lete:Error=newError('errormessage')BOM和DOM的内置对象Window、Document、HTMLElement、DocumentFragment、Event、NodeListconstdiv:HTMLElement=document.getElementById('test')constdivs:NodeList=document.querySelectorAll('div')document.addEventListener('click',(event:MouseEvent)=>{console.dir(event.target)})constfragment:DocumentFragment=document.createDocumentFragment()
声明文件在使用第三方库时,第三方库有很多的全局变量,在使用TypeScript时,TypeScript不知道这些全局变量,就会报错,智能提示也不好比如在平常使用jQuery时,直接在<script>标签引入jQuery就会有$或jQuery了,但在TypeScript中就不知道//安装jQuery:npminstalljquery//导入jqueryimport{jQuery}from"jquery";jQuery('#foo')#就会报错就需要使用declarevar定义它的类型declarevar并没有真的定义一个变量,只是定义了全局变量jQuery的类型,仅仅会用于编译时的检查,在编译结果中会被删除。import{jQuery}from"jquery";declarevarjQuery:(selector:string)=>any;jQuery('#foo');手动定义声明文件声明文件名字格式:xxx.d.ts,TS编译器会自动去扫描这类文件创建jQuery.d.ts把下面这句从上面独立出来declarevarjQuery:(selector:string)=>any;缺点:这么多库,这么多全局变量,不可能自己加,所以这些都提供有自己的声明文件下载库自己的声明文件很多的第三方库都定义了对应的声明文件库,库文件名一般为@types/xxx可以在https://www.npmjs.com/package/package进行搜索有的第三库在下载时就会自动下载对应的声明文件库(比如:webpack),有的可能需要单独下载(比如jQuery/react)//下载jQuery声明文件npminstall@types/jquery--save-dev
说明泛型的使用:当定义类型时(函数、变量、接口、类),只有在使用的时候,才只是具体是什么类型时,就可以使用泛型定义引入实现生成传入指定元素,指定长度的数组functioncreatArray(value:any,count:number):any[]{letarr:any[]=[];//需要初始化for(leti=0;i<count;i++){arr.push(value);}returnarr;}console.log(creatArray('XX',5))//['XX','XX','XX','XX','XX']使用泛型functioncreatArray<T>(value:T,count:number):T[]{letarr:T[]=[];//需要初始化for(leti=0;i<count;i++){arr.push(value);}returnarr;}console.log(creatArray<number>(22,5))//[22,22,22,22,22]多个泛型参数的函数泛型常用字母K、V、TfunctioncreatArray<K,V>(x:K,y:V):[K,V]{return[x,y]}console.log(creatArray<number,string>(22,'XX'))//[22,'XX']泛型接口在实现接口时,再定义类型//泛型接口interfaceIbaseCRUD<T>{data:T[]add(t:T):voidgetById(id:number):T}classUser{id?:number;//id主键name:string;age:number;constructor(name:string,age:number){this.name=name;this.age=age;}}classUserCRUDimplementsIbaseCRUD<User>{data:User[]=[]add(user:User):void{user={...user,id:Date.now()}this.data.push(user);console.log('saveuser',user)}getById(id:number):User{returnthis.data[id]}}constuserCRUD=newUserCRUD()userCRUD.add(newUser('XX',16))userCRUD.add(newUser('YY',17))console.log(userCRUD.getById(1))//{name:'YY',age:17,id:1646630710525}泛型类在实例化类时,再定义类型classUser{name:string;age:number;constructor(name:string,age:number){this.name=name;this.age=age;}}classUserCRUD<T>{data:T[]=[]add(user:T):void{this.data.push(user);console.log('saveuser',user)}}constuserCRUD=newUserCRUD<User>();userCRUD.add(newUser('XX',16))//saveuserUser{name:'XX',age:16}泛型约束当使用泛型时,函数逻辑中,可能并不知道该类型有这个方法或属性,而报错,智能提示也不好functionfn<T>(x:T):void{//console.log(x.lenght)//报错:类型“T”上不存在属性“lenght”。}处理:泛型继承某类、某接口一个泛型变量只能继承一个类或者接口classUser{constructor(publicname:string,publicage:number){}}//泛型继承User类functionfn<TextendsUser>(x:T):void{console.log(x.name,x.age)}//传入符合这中类型的值fn(newUser('XX',16))//XX16