自定义一个指令解决部分组件没有scopeid的问题

Demo预览:

https://sunzsh.github.io/vue-demos/#/poper-trans

代码:

https://github.com/sunzsh/vue-el-demo/blob/master/src/main.js

https://github.com/sunzsh/vue-el-demo/blob/master/src/views/poper-trans.vue

Vue.directive('scoped', function(element, binding) {
  const scopedId = binding.value.$options._scopeId
  if (!scopedId) {
    return
  }
  
  const componentTag = element.__vue__.$vnode.tag
  let target = [ ] // 需要添加scopedId的元素

  if (componentTag.indexOf('ElPopover') !== -1) {
    // popover组件
    target.push(element.children[0])
  } else {
    target.push(element)
  }
  target.forEach(item => { item.setAttribute(scopedId, '') })

})e

上期视频最后的这个问题啊

这个小伙伴猜对了

我们先来回顾一下问题啊

就是我们写好了这个动画效果

但是如果我们放在这个scoped里面

我们来看一下

这个动画就没有了

我们先来看一下原因啊

首先呢这个popover展开的这个层啊

它被挂在的是body底下

而且呢它没有这个scopeid

但是呢我们生成的这个样式

大家看一下我再搜一下

最终他生成的这个样式类名啊

他是包含这个属性选择器的

要求你必须有这个scopeid的这个属性

所以呢他永远也命中不到这个div

有同学还说

我们能不能给他加一个穿透

我们加一个试试啊

v-deep然后呢给后边这个也加一个

我们先加两个

我们来看一下它最终生成的样式

它是这样的

要求前面这个元素

必须有这个scopeid的属性

然后呢它的子元素

如果是这样的话呢

就要求因为我们放在body底下了吗

就要求body必须有这个属性

所以这个也是不现实的

所以这种方法也是不可取的

还有的小伙伴说呢

给这个popover加一个appendtobody

等于false

但是呢

我们来看它官方的组件属性里边

对于popover组件

是没办法设置这个append-to-body

它不像dialog组件儿

它是有这个append-to-body属性的

在这里

所以呢这个方法也不行

那怎么来处理呢

我们再回到这个小伙伴提的方案哈

其实呢我们在页面上可以通过

this.$options.scopeId

来拿到当前这个页面的这个scopeId

我们来看一下

大家看,所以呢我们是可以通过

给它加一个ref

ref等于

popover

然后呢我们在下边通过this.$refs

popover

然后再找到popover里的$refs的pop

这是那个组件的HTML元素

然后给它设置attribute

把这scopeid强制给它设上去

我们来看一下结果

然后呢展开,大家看动画已经有了

我们再来看这个div

大家看这个div

已经有了这个scopeid这个属性了

所以呢我们写的那个样式

是可以命中到这个div的

但是呢这样写的话呢又不是很优雅

所以呢我又想了另外一个办法

我们先把它注释掉

怎么写呢

这个也不用了

我们直接在这写一个指令叫v-scoped

等于this

然后这个自定义的指令怎么写呢

大家看这里

我们在这首先接收两个参数

一个element和一个binding

我们通过binding.value

就能拿到他传的这个this

所以呢

this.$options.scobeId就能拿到scopeid

如果没有scopeid返回,然后呢

我们下边这我先给它注释掉

先来打印一下这个element

打开这element的是span

我们需要给这个span里边的这个tooltip

也就是这个el-popper给这个元素设置scopeid

其实我们一行代码就能解决,这样

element.children[0].setAttribiute(scopedId, "")

大家看,这样就可以了

但是呢

毕竟我们写的是一个公用的指令

这样写的话呢

它就不是很公用只适用于popover

所以呢我们可以这样

我们呀先通过这个方式

拿到它的一个TagName

这个是组件的一个名称哈

我们来看一下它的值是什么

大概是这样的

所以呢我们可以根据它的规则

来去做一些适配

首先呢准备一个target数组

专门用来存放需要添加scoped元素

然后呢我们去对它进行判断

如果它是包含了ELPopover哈

我们就按照el-poper的这个

层级结构去处理

否则的话呢

我们就把element当做需要添加

scopeId的元素

然后最后呢

再通过循环

挨个的给这个他

给它里面的元素设置上scopeId

这样的话呢以后再用的时候

直接在这写一个 v-scoped="this" 就行了

然后如果其他组件需要适配

直接在这个地方写else-if就行了

最后更新于