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

* 抖音：<https://v.douyin.com/BxMsjDy/>
* B站：<https://www.bilibili.com/video/BV1Es4y1a7bP/>

> **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>

```javascript
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就行了


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sunzsh.gitbook.io/xiaoshan.bug/zi-ding-yi-yi-ge-zhi-ling-jie-jue-bu-fen-zu-jian-mei-you-scopeid-de-wen-ti.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
