20220103日记
本文最后更新于:2023年8月27日 晚上
写给自己的话
约束自己,学习
start
下列关于vue的知识,写在vueCli项目基础知识那一篇
20220103
学习成果如下:
- 使用vuecli框架技术,复习axios三层封装,调用和风天气接口,使用echarts地图渲染出浙江省级地图气温情况
20220104
- 在昨天的基础上,做如下更改
- 使用echarts地图动态渲染出六个省级地图,使用elementUI中的el-select标签选择
- 动态添加选中每一个省级地图下的市级,选中市级可查看市级的天气情况
- 根据市级使用遍历获取json的的城市id,获取未来三天的天气预报并渲染
天气预报项目End
20220105
- 复习python爬虫,使用爬虫爬取b站热榜的信息(标题,作者,点赞数,播放数,封面图片)
- 学习ts中各类接口继承和实现,泛型,es6中三点运算符
20220106
- 学习ts泛型接口,模块化,命名空间
- 使用ts模仿jquery封装写一个$.get,$.post功能
20220107(见TypeScript基础)
- 学习ts中的装饰器(类装饰器,方法装饰器,属性装饰器)
- 认识vue3.x,vite创建vue项目
- 按键修饰符@keyup
- 巩固vue项目基础,复习watch和computed
- 利用计算属性,写一个检索功能
20220108
- 使用vue仿ToDoList
- 学习localStorage存放参数
- 使用props子父组件传参
- 父组件使用标签自定义函数,子组件使用$emit调用父组件的函数
20220109
- 学习mitt插件,一个页面内多个组件间传值
- 利用@input和$emit实现父子组件双向绑定
- 了解vue3中新出的setup功能
20220110
- 使用reactive函数和ref函数创建响应式对象
- 设计自定义组件,文本,样式
- 小综合案例(切换功能栏)
- keep-alive保存状态
- 学习this.$nextTick函数
20220111
- vue3的全局变量(原型属性)
- 使用mixins抽离功能
- 使用mixin函数定义全局功能
- Teleport标签实现放置指定位置
- 小综合案例(自定义模态对话框)
20220112
- 使用toRefs函数结构一个响应式对象为普通对象,但里面的属性为响应式变量
- 在setup中写computed(计算属性)
- readonly(),传入响应式数据,改为普通数据
- watch和watchEffect的区别,setup中写法,watch监听前后值
20220113
- 使用inject接收provide传的参数(子孙组件传参)
- vueCli创建vue3集成typescript项目
- defineComponent函数
- 使用类型限制组合式api的属性及方法
- ‘vue-router’的useRouter函数和useRoute函数setup中动态路由传值
20220114
- vue路由history模式和hash模式区别,默认为hash模式
- tslint在2019年停了,项目一律使用eslint
- 配合path,query传值(?参数名=值),动态路由配合name使用params传值(路由/值)
- vuex的引入和store,mutations使用(见vuex基础),组合式api中使用useStore函数获取执行对象
20220115
- 配合组合式api学习vuex的getter(计算属性),actions(异步执行),modules(模块化)
- vuexEnd,vue3End,typescriptEnd
- 划水,思考人生,确定下一步,实现计划
20220116(详见响应式css)
- 学习css响应式标签,@media,新学flex属性
- :root 设置全局样式,设置全局变量很有用
- label,header标签
- 写一个小案例,响应式标题栏(如何收缩标题栏为一个按钮,不使用js实现点击切换)
20220117(练习springMVC防忘)
- jackson插件使用ObjectMapper类的writeValueAsString方法将对象转为json字符串
- fastjson插件使用JSON类的toJSONString方法将对象转为json字符串
- Date类转化为json字符串会变为时间戳JSON.toJSONString(new Date())
- 使用SimpleDateFormat设置时间格式,format方法传入Date类
- 在浏览器上访问json字符串,出现乱码可以在注解中添加produces = {“application/json;charset=UTF-8”}
20220118
通过HttpServletRequest的getParameter方法接收表单数据
sprinboot使用MultipartFile工具类接收文件(使用RequestParam注解指定name接收)
- getOriginalFilename方法获取文件名字
- transferTo方法将文件写入file对象
复习spring前后端交互(拦截器,mybatis)(见springboot_mybatis文件)
- 实现HandlerInterceptor接口就是一个拦截器
- preHandle 请求处理之前
- postHandle 请求处理之后
- afterCompletion 整个请求结束之后
- 使用一个类继承WebMvcConfigurer重写addInterceptors实现拦截器registry.addInterceptor(new HandleConfig()).addPathPatterns(“/user/**”);
- mybatis 标签中参数
- parameterType 参数定义传入类型,不是特别重要
- resultType 结果返回类型,如果要返回指定实例对象,需要写在配置文件中定义,也可以直接写com开始的路径 com.FSAN.demo.pojo.User
- 实现HandlerInterceptor接口就是一个拦截器
20220119
- docker使用redis(见docker安装配置redis)
- springMVC复习End
- 阿里云短信服务(验证码功能)start!
- 申请短信服务中。。。(见阿里云短信服务)
20220120
- 写一遍完整的短信发送流程,使用redis做缓存防止频繁发送,知识点:
- 使用UUID工具类生成随机数
- StringUtils工具类的hasText方法判断字符为空
- redis使用TimeUnit工具类设置过期时间
20220121
- 复习redis基础命令(见Redis学习)
- 特性
- 命令:
- select
- dbsize
- get,set
- keys *
- flushall,flushdb
- exists
- move
- expire
- ttl
- del
- type
- strlen
- append
- incr,decr
- incrby,decrby
- setex,setnx
- mget,mset,msetnx
- user:{id}:{filed} 取key名称设计
- getset
20220122
- redis学习List类型操作(见Redis学习)
- lpush,rpush
- lrange
- lpop
- lrem
- llen
- ltrim
- rpoplpush
- lset
- linsert
- set(集合)类型操作
- sadd
- smembers
- sismember
- scard
- srem
- srandmember
- spop
20220123
- java中认识jwt(见jwt基础)
- 常见jwt库:java-jwt、jose4j、nimbus-jose-jwt、jjwt、prime-jwt、vertx-auth-jwt
- Header(令牌类型,签名算法),Payload(数据声明),Signature(签名,算法生成) 组成
20220124
今天感冒非常没精神,容我休息一天,下午打扫卫生,晚上早睡,明天补上
20220125(springboot_vue_jwt项目开始)
- 前端vue3+ts+axios+element-plus,后端springboot+mybatisplus+jwt项目开始(前见springboot_vue_jwt_before)
- 做出登录页面
- 运用栅格布局
- 在el-input中使用<template #append>定义末尾(知识new)
- require 导入图片
- 验证码功能
- 学习await,async用法,import和require的区别
- element-plus 导入 ELMessage 使用消息提示
- 写拦截器统一做状态判断
- mock拦截请求返回模拟数据
20220126(before-2)
- 认识vue3的新语法糖script setup语法糖
- element-plus中icon图标的注册
- justify-content常用相关属性:
- centent 居中
- flex-start 从行首起始位置开始排列
- flex-end 从行尾位置开始排列
- space-between 均匀排列每个元素,首个元素放置于起点,末尾元素放置于终点
- space-around 均匀排列每个元素,每个元素周围分配相同的空间
- space-evenly 均匀排列每个元素,每个元素之间的间隔相等
- stretch 均匀排列每个元素,’auto’-sized 的元素会被拉伸以适应容器的大小
- 完成登录后的主页,侧边菜单栏的制作
- 制作对应的页面子路由配合菜单栏跳转
20220127(before-3)
- 完成头像和用户信息接口并使用
- 完成个人中心页面
- 路由path query传参
- validator 使用自定义校验,自定义错误 new Error
- @click.native 使用原生事件,用于自定义组件如,在router-link中使用点击事件,但我在vue3中使用会报错,原因不详,就直接使用@click,发现正常使用
- 退出账号功能
- 发起请求退出账号
- 使用clear方法清除localStorage和sessionStorage信息
- 清除vuex中的token
- 跳转到登录页
- 学会在main.js中全局注册element-plus组件
- 导入使用as改名
- 循环遍历使用createApp(App)下的component方法注册组件
- component 函数,传入两个值,注册名和组件名,全局注册
20220128(before-4)
- 将侧边菜单栏改为动态菜单
- 写mock模拟返回
- 使用v-for配合component标签,动态添加icon图标
- 使用路由拦截器请求路由返回(通过请求后放行)
- 使用addRoute函数添加子路由
20220129(before-5)
- sessionStorage 和 localStorage的区别
- localStorage 是跨选项卡共享数据,同步刷新的
- sessionStorage 则是单页面独立数据
- 将获取的动态路由和用户权限列表放入vuex
- 添加tabs标签页,将tabs标签页独立做一个vue组件,并将配置交给vuex管理
20220130
有事
20220131
除夕夜忙
20220201
春节忙
20220202
回老家忙
20220203
沉浸在过年气氛中
20220204(见before-6)
开始学习,重新振作起来:
- 将tabs标签页动态和路由绑定,点击切换和侧边栏同步(tabs的name值设置为侧边当前name就行了,都是路由)
- 新函数findIndex,根据自定义回调方法返回符合的数组数据下标,避免tabs重复添加
- 删除tabs标签时处理为当前标签时的情况,设置首页不可删除
20220205(见before-7)
- 使用filter函数,获取满足指定条件的数组中的数据
- 深度学习路由守卫中的next效果(放行和中断)
- next() 只有这个是对路由的放行
- next(‘/login’) 类似只是拦截到to为’/login’的路由,并重新执行beforeEach((to, from, next)
- next({…to, replace: true}) 拦截路由信息,判断是否有路由,没有就再次执行beforeEach((to, from, next),replace: true让用户禁止使用浏览器后退
- 解决动态路由刷新问题
- 问题:在添加路由之后第一次访问被添加的路由会白屏
- 原因:在路由刚被加载的时候就立刻访问被添加的路由,这时addRoute还没有执行结束,所以找不到
- 解决:使用next({…to, replace: true})拦截to的路由信息,如果没有则会再次执行beforeEach((to, from, next),这时可以通过一个参数来控制不获取路由,直接next()
- 浏览器刷新时,保留当前的标签
- 在app.vue中监听$route的变化,将路由中的title和name添加到tabs即可
- 使用退出按钮时,恢复默认tabs标签
- vue3中slot插槽的变化,都由
#统一(v-slot)
20220206(见before-8)
- 编写菜单页表格
- 编写添加对话框功能
- 复习linux中docker挂载和映射
20220207(before-9)
- es6中new Promise讲解,解决回调地狱问题
- resolve,回调参数,表示处理通过,给下级then接收
- reject,回调参数,表示处理错误,给下级catch接收
- 将具体的接口操作过程交给vuex管理
- action配合promise对象,这样就不用在vue中导入api,只要导入dispatch即可(个人理解)
20220208(before-10)
- 完善添加对话框
- 关闭事件清空form数据,reset表单
- 实现添加数据和编辑更新接口调用
- 提交更新后的数据和添加数据使用一个函数,通过是否有id判断是update还是add
- 删除数据接口调用
- 使用Pop confirm二次提示删除
20220209(before-11)
- 角色界面的多选表格,搜索、删除和批量删除操作
- 监听多选数据是否为空
- 批量删除和删除的按钮事件设置为一个,是否传递id判断是删除还是批量删除,将id放入list后到调用接口即可
- 分页功能
- current 当前页
- size 显示数
- total 总数据条数
- 当前页显示数和每页显示数改变时修改获取数据的参数并重新获取数据
- element plus组件默认英文改中文
- main.js 中导入element-plus的中文插件,在使用element-plus时带上即可
20220210(before-12)
- mock的url中使用RegExp函数可以使用正则的模糊匹配
- vue 中的watch(监听属性)和computed(计算属性)的区别
- computed可以观察多个数据,watch只能是一个数据
- computed可以直接生成一个新的数据渲染致视图中,watch是修改本身已经存在的数据
- computed不可以执行异步的,因为需要返回值,返回值是由js主线程控制,watch可以执行异步的,因为不需要返回数据,参考定时器(定时器是属于异步的线程)
- 角色管理中新增,编辑功能
20220211(before-13)
- 完成角色管理中分配权限展开对话框
- tree 树形控件
- data 数据源
- props 指定label和children属性名
- show-checkbox 节点是否有选中框
- node-key 指定唯一值(key)
- 通过设置ref的setCheckedKeys方法设置对应key值的状态
- 通过ref对象的getCheckedKeys方法获取选中的keys
- tree 树形控件
- 完成用户管理基础table
20220212(before-14)
- 完成用户管理(新增,编辑,分配角色,重置密码)
- 使用@close清空对话框数据,不能用before-close属性(直接改变dialogVisible这种做法不会调用before-close事件)
- 傻傻的踩坑:rules写成roles,也没报错,硬找了半小时
20220213(before-15)
- 完成分配角色
- 确认事件
- 重置密码
- 删除和批量删除
- 搜索
- vue2中使用的this.$confirm在vue3中需要导入ElMessageBox,然后ElMessageBox.confirm
- flex-flow是flex-direction(控制盒子内元素排列顺序)和flex-wrap(规定flex容器是单行或者多行)复合型,如flex-flow: column 就是flex-direction的属性,同:flex-direction: column
- 使用default-openeds设置刷新浏览器后的默认展开sub-menu(配合动态路由)
20220214(before-16, after-16.5)
- 使用全局方法控制页面中的每一个按钮权限
- 前端完结,开始springboot后端接口编写,技术栈:
- springboot
- mybatis plus
- spring security
- lombok
- jwt
- redis
- hibernate validatior
- 初始化springboot+mybatis-plus项目
- idea快速创建springboot
- 官网复制mybatis-plus依赖添加即可
- 学习 Lambda 表达式
- 数据库搭建(表如下)
- sys_menu (menu控件数据)
- sys_role (角色管理数据)
- sys_role_menu
- sys_user (用户管理数据)
- sys_user_role
- 写一个返回的统一封装类
20220215(after-17)
- 写好对应的mapper类和model
- 创建config类,配置分页插件
- 在返回包中写全局异常反馈处理
- @ResponseStatus 注解,设置返回的消息模板,如返回400
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- @ExceptionHandler 注解,捕获某种异常类型,如运行时异常
- @ExceptionHandler(value = RuntimeException.class)
- 认识并引入spring security (安全框架),jjwt,redis
- 配置security默认用户名和密码
20220216(after-18)
- 使用redis报错,于是修改maven镜像源,发现自己原来没有settings.xml,去找了个配置好jdk8和阿里云镜像的cv上,在idea中搜索maven修改对应的配置目录,终于正常了(浪费一小时)
- 在config新建RedisConfig文件,配置Redis序列化(为了让存入的数据和拿出的是一个格式,设置value为json格式)
- 登录页面大致流程
- 前端进入页面发送请求给后端,后端返回图片key和code并存入redis
- 前端发起登录请求,后端通过key在redis中拿到code进行比对,返回登录成功或失败
- 导入并使用google captcha(google验证码生成器)
- 因为原来的com.google.com已经无法使用,现在使用com.github.axet,在mvn上搜索即可
- 在config下创建配置文件,设置生成图片的宽高等属性
- 在controller下创建AuthController和BaseController,在BaseController中注入常用的Bean,然后再其他控制处使用extends继承即可
- AuthController中写获取验证码的方法(知识点:)
- UUID.randomUUID() 生成UUID(32位的随机数字)
- 注入Producer(就是我们上面导入的验证码生成器)
- createText() 创建五位数的随机验证码
- cretaImage() 根据传入的字符类型生成图片
- ByteArrayOutputStream对象配合ImageIO类根据文件创建IO流
- Base64的前缀是 “ data:image/jpeg;base64, “
20220217(after-19)
- 配置security
- @EnableWebSecurity 加载security相关安全策略的配置
- @EnableGlovalMethodSecurity 指定校验的时机
- 看了这么多security,太陌生了,虽去补课(见security基础)
20220218(security 基础)
- 使用 fastjson 的 @JsonInclude 注解,常见如下:
- ALWAYS 表示全部序列化,null和空字符串都会序列化
- NON_NULL 好理解,就是值为null就不序列化
- NON_EMPTY 以下情况都不会被序列化:
- null
- 空字符串
- 空集合
- 空数组
- Optional 类型的,其引用为空
- AtomicReference 类型的,其引用为空
- jackson的ObjectMapper类介绍和使用
- ObjectMapper类是Jackson库的主要类。它提供一些功能将转换成Java对象匹配JSON结构,反之亦然。它使用JsonParser和JsonGenerator的实例实现JSON实际的读/写
- ObjectMapper类的方法
- .enable(SerializationFeature.INDENT_OUTPUT) 美化输出
- .registerModule(new Jdk8Module()); jackson支持Optional特性
- .writerValueAsString(对象) 按照@JsonInclude配置序列化
- redis和jjwt工具类保存
20220219
开学麻烦
20220220
使用@TableName注释配置mybatis plus的映射,如数据表为sys_user,按道理说,实体类的自动映射名称是SysUser,要是实体类名称对不上,如取名为User,就可以在类上使用@TableName(value= “sys_user”)直接配置映射表名
写UserDetailsServiceImpl实现UserDetailsService,重写loadUserByUsername方法(UserDetailsServiceImpl记得加上@Service注解)
- 在这个方法中去查询数据库,在查询不到异常的时候,也可以通过直接使用 throw new RuntimeException(“出现异常”); 来自定义抛出异常,会被security自带的异常处理收集到
java中注释加上TODO的作用(TODO占位,表示接下去该写的但是还没写的)
java8中可以使用Objects.isNull()判断是否为空,源码为 return obj == null
写一个实体类实现UserDetails,重写所有方法,并将返回的布尔类型全改为true
QueryWrapper到LambdaQueryWrapper的演变(https://blog.csdn.net/qlzw1990/article/details/116996422)
20220221
- 启动spring security,在测试时如出现There is PasswordEncoder mapped for the id “null”报错,则是明文密码的原因,需要在数据库的密码前面加上 {noop},暂时这样写
- 关于数据库中密码前面的大括号
- 登录流程—–输入账号密码之后,security经过一系列过滤器后到达UserDetailsService,返回UserDetails对象数据,在权限的过滤器中判断UserDetails对象中的用户名和密码能不能和输入的对上,但是UserDetails对象由我们自定义之后,默认使用的PasswordEncoder要求数据库中的密码格式为: {id}password,它会根据id去判断密码的加密方式,但是我们一般不采用这种方式,所以就需要替换PasswordEncoder
- 配置类中passwordEncoder使用BCryptPasswordEncoder配置密码加密
- new BCryptPasswordEncoder().encode(“FSAN”) 得到“FSAN”的随机加盐加密后的密文
- new BCryptPasswordEncoder().matches(“FSAN”, “$2a$10$qNin1NOP265Zqme378882uxos.haI3Da9JCi3gPg65GOHb/5t1oGO”) 判断密文是否为加密后的FSAN,返回true为相同
20220222
- 写登录的controller,和service
- 登录接口一般为post接口,数据通过json格式在请求体中传递,所以使用@PostMapping和@RequestBody
- 接收参数直接使用实体类接收即可
- 对登录接口进行放行(不需要登录security也能调用接口),配置security
- 关闭csrf
- 不使用session获取SecurityContent
- 配置不登录就可以访问的接口(匿名登陆)
- 再service中使用AuthenticationManager authenticate 进行用户认证
- AuthenticationManager需要先在security配置类中先重写后注入
- 在service使用@Autowired引入之后使用authenticate,需要传入Authentication类型
- 创建UsernamePasswordAuthentication对象,因为UsernamePasswordAuthentication源码中有实现Authentication对象
- 使用new构造UsernamePasswordAuthentication对象时需要传入用户名和密码(user.getUsername,user.getPassword)
- 使用objects.isNull判断authenticate方法的返回值就知道是否有权限登录
20220223
- 使用redis的工具类,保存用户的id和完整的用户信息
- 复兴登录流程,整理思路
20220224
写材料
20220225
- 定义jwt过滤器(建立filter包)
- 定义class继承OncePerRequestFilter重写doFilterInternal方法
- 使用filterChain.doFilter(request, response);对过滤器放行
- 在过滤器中需要实现的操作
- 获取请求过来携带的token
- 解析token
- 向redis获取用户信息
- 将用户信息存入SecurityContextHolder
20220226
- 退出登录功能实现
- 写controller和server实现类
- 需要实现的操作
- 从SecurityContextHolder中拿取用户id
- 删除redis中的数据
- 配置项中antMathers()
- permitAll(),设置登录或者不登陆都可以访问
- anonymous(),设置不登陆可以访问
- 配置项中anyRequest()
- authenticated() 其他用户在认证后都可访问
20220227
- 授权的实现
- 首先在security配置类中使用@EnableGlobalMethodSecurity(prePostEnabled = true)开启权限控制方案
- 然后在需要设置权限的方法上使用@PreAuthorize定义所需要的权限即可
- 权限列表的实现
- 在UserDetailsServer实现类中获取权限列表并存入UserDetail
- 在LoginUser实体类中添加权限列表字段(主要涉及的是List列表中数据类型的流转换)
- 在分析token的过滤器中就将权限列表放入UsernamePasswordAuthenticationToken中
- RBAC权限模型
- RBAC权限模型(Role-Based Access Control)即:基于角色的权限控制。这是目前最常被开发者使用也是相对易用,通用的权限模型。
- 数据库设计:用户表(user),权限表(menu),角色表(role),角色权限关联表(role_menu),用户角色关联表(user_role)
- 使用数据库中的left join on 联表查询(多对多查询)
20220228
- 完成数据库的根据用户id查询权限列表操作,难点:
- 多次使用left join连表
- 使用distinct去除重复(因为一个用户可能有多个角色,每个角色的权限会有重复)
- 实现Serializable表示该类可以序列化,必须要加上serialVersionUID属性
- 完成菜单表的实体类编写
- 使用mybatis-plus做多表联查还是得自定xml配置文件
- 修改UserDetails获取的权限列表
20220301
- 自定义异常处理介绍
- 如果是认证过程出现的异常会被封装成AuthenticationException然后调用AuthenticationEntryPoint对象的方法取进行异常处理。
- 如果是授权过程中出想的异常会被封装成AccessDeniedException然后调用AccessDeniedHandler对象的方法取进行异常处理。
- 所以如果我们需要自定义异常处理,我们只需要自定义AuthenticationEntryPoint和AccessDeniedHandler然后配置给SpringSecurity即可
- 自定义实现类
- 创建AuthenticationEntryPoint实现类,重写commence方法,使用HttpStatus枚举类返回401(用户认证异常)
- 创建AccessDeniedHandler实现类,重写handle方法,使用HttpStatus枚举类返回403(权限不足异常)
- 两个实现类最后都需要设置响应体格式返回json字符串,写为一个WebUtils工具类
20220302
- 在springMVC的配置类中配置spring的跨域问题
- 在security的配置类中配置security的跨域问题
- 使用@PreAuthorize权限注解中
- hasAuthority 传入单个字符串表示需要权限@PreAuthorize(“hasAuthority(‘system:test:list’)”)
- hasAnyAuthority 可以传入多个限制权限@PreAuthorize(“hasAnyAuthority(‘system:test:list’,’system:test:add’)”),表示只要拥有这些权限任意一个即可访问
20220303
- 自定义权限认证
- 获取当前用户的权限
- 判断用户权限集合中是否存在authority
- list集合直接使用contains判断是否有某个字符串
- 使用component注解传入自定义bean名,然后在@PreAuthorize权限注解处使用@调用自己定义的权限方法,如:@PreAuthorize(“@hasMyAuth(‘system:test:list’)”)
20220304
- 自定义认证成功和失败处理器(拓展)
- 实现对应接口,重写方法
- 添加配置类
- 源码接口中的default修饰表示可重写也可以不重写
- 注销成功处理器
- 实现LogoutSuccessHandler
- 添加配置类
20220305
- 梳理流程
- 从UserDetails认证开始,无查询到用户即可抛出运行时异常,被AuthenticationEntryPoint接收时,查看authException即可
- 认证通过之后的操作(添加jwt和处理redis数据)也可以写在认证成功处理器中
- security基础结束
- 开始自己写一次jwt登录流程,了解配置类中配置项
20220306
- 复习spring security权限认证流程,redis缓存和jwtToken
- debug 自定义错误异常
20220307
完善流程,添加CURD
security学习结束
20220308
- 继续之前的Vue前后端项目的后端开发
- 认识@RestControllerAdvice注解,主要配合@ExceptionHandler使用,统一处理异常情况
- 认识@ExceptionHandler,设置捕获某种异常类
- 认识@ResponseStatus注解,设置一个异常类返回状态,如设置404及返回消息为No such order,@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = “No such order”),可以配合@ExceptionHandler注解一起使用
20220312
- gird布局使用自适应布局,使用ul,加上最大宽度即可居中
- auto-fit
- auto-fill
- -webkit-box-reflect: below; css3投影
- animation 动画效果
- defineProps vue3新api,类似props