前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在项目中使用 vue-awesome-swiper 遇到的问题

在项目中使用 vue-awesome-swiper 遇到的问题

作者头像
Chor
发布2020-03-09 10:35:58
1.4K0
发布2020-03-09 10:35:58
举报
文章被收录于专栏:前端之旅前端之旅

问题复现

最近做的商城项目需要在首页展示一个轮播图,秉承着“有现成轮子就绝不自己写”(其实是懒和菜)的想法,在网上搜索了一下,最后选择使用 vue-awesome-swiper。安装和使用就不说了,可以直接看 GitHub 的文档。按照文档写完基础结构后,实际使用的时候遇到了几个问题:

  • 图片轮播到最后一张时自动停止,无法循环播放
  • 分页器不显示
  • 无法修改分页器样式

前两个其实是一样的问题,我这里轮播图的数据放在 banners 里,一开始没赋值的时候默认是空数组,没有数据,所以这时候会导致轮播图运行不正常。解决这个问题只需要在 swiper 加一个判断就好:v-if="banners.length != 0"。第三个问题则是因为 style 标签使用了 scoped 声明,导致无法修改第三方组件库的样式。之前写单文件组件都是习惯性地加 scoped,没有考虑太多。这次遇到了问题,所以花时间研究了一下这个东西,然后查找了一些合适的解决方案,在这里做一个记录。

为什么需要 scoped

官方文档的介绍: https://vue-loader.vuejs.org/guide/scoped-css.html

为了实现样式的模块化、私有化,防止全局样式污染,我们可以给单文件组件中的 style 标签添加 scoped属性,这样,里面书写的 CSS 样式就只能应用于当前的组件。其原理是通过 PostCSS 实现的,经过编译后,template 中手写的元素会与 style 中的样式通过自定义属性 data-v-xxx 形成对应。也就是说,我们写的样式实际上只对具有对应自定义属性的元素生效,而由于这样的元素只存在于组件模板中,所以确保了样式只对当前组件生效。例如:

代码语言:javascript
复制
// test.vue
<template>
    <div class="test">
        <a><img></a>
    </div>
</template>
<style scoped>
    div img{
        width:100%;
    }
</style>

上面的代码经过编译后,实际上会变成:

代码语言:javascript
复制
// test.vue
<template>
    <div class="test" data-v-1a0c5ce5>
        <a data-v-1a0c5ce5>
            <img data-v-1a0c5ce5>
        </a>
    </div>
</template>
<style scoped>
    div img[data-v-1a0c5ce5]{
        width:100%;
    }
</style>

如果没有加 scoped ,那么宽度 100% 这个样式会作用于所有的图片;由于使用了 scoped,所以这个样式只对当前组件生效。

同样的,如果是父子组件:

代码语言:javascript
复制
// 父组件
<template>
    <div class="parent">
      <son>
          <span>我是插槽</span>  
      </son>
    </div>
</template>

<style scoped>
    .parent .son{
        border:2px solid red
    }
    .parent .son h1{
        color: green
    }
    span{
        color:yellow
    }
</style>

//子组件
<template>
    <div class="son">
          <h1>我是子组件</h1>
        <slot></slot>
    </div>
</template>

我们会发现,可以在父组件中修改子组件根元素(div.son)以及子组件插槽的样式,但是无法修改子组件子元素(h1)的样式。在控制台中可以看到,代码编译后是这样的:

代码语言:javascript
复制
<div class="parent" data-v-1a0c5ce5>
    <div class="son" data-v-1a0c5ce5>
        <h1>我是子组件</h1>
        <span data-v-1a0c5ce5>我是插槽</span>
    </div>
</div>

<style>
    .parent .son[data-v-1a0c5ce5]{
        border:2px solid red
    }
    h1{
        color: green
    }
    span[data-v-1a0c5ce5]{
        color:yellow
    }
</style>

这是因为,不管是子组件根元素还是子组件的插槽,最终都是实际书写在父组件的 template 中的,所以父组件中书写的样式能够对应地在父组件模板中找到 DOM;而子组件的子元素(比如上面的 h1),它实际上是在子组件模板书写的,此时没法通过自定义属性建立样式与 DOM 的对应关系。因此这个样式不生效,这样也就防止了在父组件的层面上修改子组件的样式。

回到一开始的问题

再回到一开始的问题,轮播图的结构大概是这样的:

代码语言:javascript
复制
<template>
  <swiper>  
      <swiper-slide v-for="item in banners">  
           <!--渲染部分-->
      </swiper-slide>  
      <div class="swiper-pagination" v-for="item in banners" slot="pagination"></div>  
  </swiper>  
</template>

div.swiper-pagination 只是包裹每个圆点 span.swiper-pagination-bullets 的容器,实际上没有在 template 中直接书写 span.swiper-pagination-bullets 。这里我看了下源文件,还是没有找到这几个圆点是怎么来的,但可以肯定是动态生成的,所以猜测可能是组件样式的 scoped 为样式和 DOM 建立对应关系的时候,此时这些圆点还没有生成,也就是说,圆点“错过了”添加自定义属性的过程。当然这个只是猜测,如果有大佬知道这里面的具体过程,也欢迎在下面评论区指出。

如何修改第三方组件库的样式

虽然 scoped 可以防止全局样式污染,但是给我们修改第三方组件库的样式带来了困难 —— 就像上面的问题一样,这些第三方插件通常都是项目中的子组件,而我们又需要根据项目需求修改组件样式。那么怎么办呢?这里记录一些可能的解决方案:

  • 去掉 scoped:破坏样式的封装,不推荐
  • App.vue 中书写全局样式,不推荐,理由同上
  • 新建一个 css 样式文件,在里面书写需要覆盖的样式,并在 main,js 引入该文件
  • 同时使用带 scoped 与不带 scopedscript 标签,在后者书写需要覆盖的样式
  • 使用深度选择器实现样式穿透: 对于普通 CSS 或者 stylus,使用 >>>;对于 sass 和 less,使用 /deep/。以上面代码为例,如果要实现样式穿透,可以这么写:
代码语言:javascript
复制
  <style scoped>
    .swiper-pagination >>> .swiper-pagination-bullet-active{
      background-color: var(--color-tint);
    }
    /* 或者是
    .swiper-pagination /deep/ .swiper-pagination-bullet-active{
      background-color: var(--color-tint);
    }
    */
</style>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题复现
  • 为什么需要 scoped
  • 回到一开始的问题
  • 如何修改第三方组件库的样式
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档