19.Vue技术栈开发实战-Tree组件实现文件目录-高级实现
首先把上节课实现的tree的逻辑进行封装,封装成一个组件,能够达到一个复用的效果。
第二部门增加一个操作目录,每个目录,每个文件都应该可以操作,比如删除这个文件,重命名这个文件的文件名或者目录,
3.在这个组件里面传入多个值,而且每次做更新会同时更新这多个值,如果一个值在组件内需要更新的话, 我们可以用v-model,如果多个值呢?我们来学习一下替代方案。
最后给这个组件完善一下,增加一些钩子函数。来满足我们实际业务中的需求。
开始
首先我们要把这个tree封装成一个组件,创建folder-tree这个组件,
index.js内,先导出去
这个地方,我们只用一个tree组件。
给这个组件一个name值
之前的tree组件我们只传入了转换为树状数据的data数据,然后传进去了一个render函数。
我们现就要把它作为属性传给folder-tree组件了。引入folderTree,然后注册这个组件,并使用这个组件。
我们之前传入的数据是转换后的,整理好的树状的数据,实际我们把它封装成一个组件,那么我应该在用的时候,尽量的减少我们自己的再做的操作,要不然这些东西都在这里做的话,就没有必要在封装了。封装的目的就是为了在复用的时候减少我们的工作,
所以我们直接传入folderList文件夹的列表数据和文件的列表数据,在组件内不让它去做转换。
转换的数据就是我们传递进来的属性。
内部定义 folderTree
res[0]是文件夹数组,res[1]是文件数组。
把之前的render函数赋值到组件内部
复制到了组件的内部
样式剪切到组件的内部
剪切到了组件的内部
声明周期mouted钩子函数内,先调用一次,如果这个时候传进来有数据,在这里就会做这个工作。
如果一开始没有,是异步的传进来的数据呢?所以我们要监听folderList和fileList变化的时候,都要做处理。
和之前的效果一样
操作目录
接下来,来看操作目录这块。
我们要在render的这个地方,给每个元素都加一个下拉菜单。
下拉菜单用Dropdown这个组件。里面第一个元素是用来,显示下拉列表的元素。在jsx里面,view的组件必须用带前缀i-的方式
复制过来是大写的Icon。
我们要改成小写的方式
给它设置一个size,我们的size是一个数值类型,不是字符串的类型,所以这里我们要用花括号括起来
每一条都这么宽,想让button始终显示在最右侧
要不然文件名,不一样长就对不齐了。给它加一个class属性
没有效果,因为它外层裹了一个ivu-dropdown
tree-item里面直接子元素的 .ivu-dropdown
定义里面的列表
用dropdownMenu让它作为一个插槽。
移出来,和i-button是同级别的。
鼠标放上拉颜色怪怪的,背景是灰色,并且宽度没有100%的背景色。可能是被我们tree里面的一些样式给覆盖了。
样式被覆盖,需要我们自己写一下样式。设置了 下面的css ,没有效果
应该还是一些样式的权重不够。看到这个ul的padding-left还是有的
勾选去掉就可以了
我们给这个ul加类名ivu-dropdown-menu
item同理也加上类名为ivu-dropdown-item,这样样式就正常了。
定义两个属性,一个是文件夹操作列表,一个是文件操作列表。这里没有设置默认值,如果是空数组的话,说明它不需要下拉菜单,所以之类我们没有设置默认值,直接让它是一个aarray类型,到时候直接是否为空就直接判断这个数组是否是undefined,如果是undefined说明它没有传入值。
没有传dolerDrop没有传就直接不显示这个dropdown按钮了。
调用组件的时候,传入这两个属性
渲染传进来的菜单。对dropList做一个映射。return里面写我们jsx的内容。
绑定一个name属性,方便我们后面知道点击了是哪一个
为了区分开,把菜单的名称改一下
dropdown设置右边顶部对齐。
页面宽度比较窄的时候会显示在左侧,
根据屏幕的边缘智能判断,显示在那一边
dropdown添加事件
dropdown有个on-click事件
在jsx里面我要用on-前缀来标识,这是一个绑定的事件,事件名写在后面
点击删除文件夹
点击重命名,显示输入框,输入新的名字
重命名
首先要有一个全局的标识。
方法需要绑定参数,用bind在this上面去绑定
click事件原生返回的name值,它会拼在我们自定义的参数 后面
所以这里我们第一个参数是data,第二个参数是name
直接还可以再简写一下。如有这个data.type字段的话就用folder。,没有的话就用file
有个这个标识之后,我们就可以判断了。如果当前编辑的id等于拼接的id那么,
那么就显示i-input,同时给i-input绑定上input事件,
定义方法,它的参数就是当前修改后的内容
定义变量currentRenamingContent
点击重命名
文本框后面,还需要两个按钮,这里因为jsx里面要求只有一个根节点,所以用一个span标签包裹起来。
加上两个按钮,然后输入框 让他短一点,加上一个class类名
这里还是用计算的属性,100%减去80px
按钮设置为small 并且类型是texxt
点击重命名
把状态抽到上面
如果正在重名,那么dropDown也不显示
保存修改事件
点击对号以后,要替换原来的内容
还是需要把data参数传进来
接下里要在里面遍历一下,如果你当前修改的是文件夹目录中的一个目录的名字的话,你是要遍历文件夹列表。
定义i为-1, 如果type类型是folder的话,也就是文件夹
获取文件list的长度,然后循环,如果当前的item的id等于修改的id,那么就把item的name替换为修改的内容。并且用splice方法把文件夹list的item元素移除,再替换修改后的进来。
如果是文件列表的话。下面就是循环fileList
把这部分抽离出来封装成一个公共的方法,下面调用的时候 直接传参数list进去就可以了。
让文本框消失
事件绑定错了值了,绑定到了差号上了。移动到对号上
缺点,我们直接在这个组件内修改filstList和folderList肯定是不行的
修改父组件内的值
引入深拷贝
修改没有效果
先把修改后的值return 出来先
通过事件抛到父组件内去修改。在父组件内,我们绑定了两个值,一个folder-list一个是file-list .如果只绑定一个值的话 ,我们可以用v-model来做,但是我们这里绑定了两个值。
这里我们用之前讲过的.sync修饰符。父组件间内,这里都加上sync修饰符。
子组件内怎么更新呢?update冒号 这是固定的。
然后要更新哪个值,folderList是父组件传过来的值。
修改文件同理
这里是拿到了name赋值给title,所以我们修改了name的值 也是可以的。
同时这里监听了两个list的变化,一但有变化就重新触发 转换的方法,上面把name赋值给title,所以我们修改的时候修改的name值也是对的。
删除操作
删除要提醒用户,是否要删除
封装一个方法,判断是删除文件夹还是文件。
然后下面判断是文件夹还是文件。
确定要删除执行的方法
判断是否是文件夹,如果是文件夹,那么更新的就是folderList,如果是文件更新的就是fileList了。
判断要删除的是哪个对象, 就深拷贝哪个对象
删除操作可以使用filter过滤操作,return的就是不需要过滤掉的,就是你要的
返回的是id不等于当前要删除的id的。那就是删了以后剩下的元素。
emit事件
删除后,文件夹就合住了 需要重新打开。这样体验就很不好。
删除后,文件夹保持展开的状态
tree组件要给当前的这个item一个属性,设置一个值,是否展开子节点,如果设置为true就会展开这一节
需要一个方法,传入一个id。你要展开哪一个目录,就把文件夹id传进去。
在util里封装一个方法。用map方法做一个映射。
如果是文件夹,并且找到了这个id。那么就展开这个节点
如果item.children里面有一个children的expand为true的话 那么就返回。
所以这里的判断就是判断这个点的子节点有一个是展开的。那么就展开当前这个节点。
否则就不展开。
最后返回当前的item
最后把返回的新数组 return出去
在组件内使用一下
调用展开的方法
没起作用
放在this.$nextTick里面执行试一下
有效果了
刚才没起作用的原因:可能是删除之后,视图还没有更新完 我们就去展开这节点,所以有问题 。
钩子函数
前端删除了,但是后端的服务删除报错了。那么这样前后端的数据就不一致。
所以点击删除 ,应该先去调用接口去做删除操作。删除成功了再往下继续。
这里就引入钩子函数。
返回一个Promise。这里我们写的是promise,实际的开发过程中,应该调用的是一个接口。这里我们暂时用Promise来代替。
模拟一个数据的延迟2秒后 成功返回。
组件内接收,方法
默认可以不设置。不设置的话,就是你比较有信心,不需要这样的一个钩子。
如果有这个函数。那么后面的操作都放在这个函数的then里面。
报错了就提示一下
把展开操作移到上面去
folderId也移到上面去。
我们现在错误设置的为null。那就是没有错误
2秒后成功删除
这里改成错误的
本节代码
结束