5

由于上篇文章内容太多,导致SF编辑器有点卡,所以新开辟了一篇,也方便阅读。

elementUI样式是全局的

之前在用mint-ui的时候每个组件里面都有style标签,样式都是内部的,公用的写在了mint-ui/lib/style.css文件里并且该样式文件就是在mint-ui项目里,但是element组件里都没有style标签,翻看了一会,发现element可以自定义主题,而mint不可以,这样element的样式全写成了全局的,这样方便用户配置主题。样式文件写在packages/theme-default/src内,打包element的时候会将theme-default这个独立的库放到打包好的文件夹内。theme-default针对每个组件有个对应的css文件,index.css去@import

@import "./base.css";
@import "./pagination.css";
@import "./dialog.css";
@import "./autocomplete.css";
@import "./dropdown.css";
@import "./dropdown-menu.css";
@import "./dropdown-item.css";
@import "./menu.css";
@import "./submenu.css";
@import "./menu-item.css";
@import "./menu-item-group.css";
@import "./input.css";
@import "./input-number.css";
@import "./radio.css";
@import "./radio-group.css";
@import "./radio-button.css";
@import "./checkbox.css";
@import "./checkbox-group.css";
...

style直接写在组件上会起作用

<topic :style="topicDialogStyle"></topic>

 computed: {
    topicDialogStyle() {
      return {
        maxHeight: "65vh",
        overflow: "auto"
      }
    }
  }

上篇提到class直接写在组件上面是会渲染到组件的根节点上面,惯性思维,认为style也会在跟组件上起作用,测试了下是会起作用的,
如果组件的style都用scoped修饰,那么每个组件的样式都是在本组件起作用,即使className渲染到了子组件的根节点,在父组件中定义的相同className的style也不会起作用,因为加了scoped以后组件的每个HTML标签都被加了一个data属性,

clipboard.png

1的地方是根节点,有两个data属性,这个不知道为啥,里面的子节点都是一个data属性,并且都是相同的。再看看vue对加了scoped的style做了啥,

clipboard.png
clipboard.png

中括号里就是data属性,每个组件data属性都不同,保证了每个组件scoped的样式只在当前组件中有效。既然父组件中定义的样式对子组件无效咋办,有很多解决办法:

  • 利用class可以在组件上直接写,子组件可以约定不同的className,子组件里面写几套style
  • 通过props将在父组件定义的style对象传递进去
  • 在父组件中再开辟个不加scoped属性的style,不过这么写可能污染到其他组件的样式。
  • 在子组件添加style属性,直接影响子组件根元素的样式

发现个奇怪的现象,在父组件中设置line-height(是scoped)子组件的所有行高都受影响,也就是所有的子元素都继承了这个属性,不设置行高默认为normal,所以解决办法就是给子组件的外层设置line-height:normal

style直接写在组件上面,会对根元素起作用,

<el-input-number size="small" :style="{color:'blue'}"></el-input-number>
<el-input-number size="small" style="color:blue"></el-input-number>

clipboard.png

"vue": "2.2.2",不知道什么原因,后续再看。

自定义element dialog宽度

由于style 加了 scoped ,所以里面每个样式都是CSS [attribute] 选择器只对加了attribute属性的标签有效,而dialog很多是全局样式,想改变dialog的高度写在scoped里面是无效的,所以可以写在不加scoped标签的style里面,

clipboard.png

custom-class Dialog 的自定义类名 string — —

通过custom-class props去控制dialog的总体样式,同时要注意改classname的唯一性,以防污染其他组件。

router-view标签创建的命名路由并不会在每次切换路由的时候销毁

app.vue

<template>
  <div id="app">
    <router-view name="header"></router-view>//头部有搜索框和logo
    <router-view name="nav"></router-view>//tab导航栏
    <router-view></router-view>
  </div>
</template>

router/index.js

{
      path: '/',
      name: 'Login',
      component: Login
    },
    {
      path: '/index',
      name: 'Index',
      components: {
        default: Index,
        header: Header,
        nav: Nav
      }
    },
    {
      path: '/paperDetail',
      name: 'PaperDetail',
      components: {
        default: PaperDetail,
        header: Header,
        nav: Nav
      }
    },

因为登录页是独立的,不需要头部和导航栏,所以要使用命名路由去动态匹配除了登录页的其他页面,本以为这么动态匹配的header.vuenav.vue是在导航栏切换的时候被销毁的,无意间发现beforeMountbeforeDestroy钩子函数并不会在导航栏切换的时候调用,(beforeRouteEnterbeforeRouteLeave任然会被正常调用,调用顺序是enter->watch route->leave,)那么这么就不会增加格外的内存开销,就等同于写死组件在根组件:

<template>
  <div id="app">
    <header></header>
    <navbar></navbar>
    <router-view></router-view>
  </div>
</template>

正如官网所述,

clipboard.png

小结:针对不同路由需要不同的数据话,可以去监听路由的变化,但是这个监听只针对复用组件,比如header.vue,对于paperDetail.vue这种没有复用的组件是无效的。

设置position:absolute对没有加position定位的父组件不会起冒泡效果

<div class="top-pane" @click="handleItemClick" v-else>
      <ul class="blue-pane" @click="handleUlClick">
        <li class="normal-line play-button-pane" @click.prevent="handleBtnClick" v-show="showPlayButton">
          <img src="../assets/imgs/play-btn.png" alt="">
        </li>
      </ul>
    </div>

css

.top-pane {
 .blue-pane {
      height: 250px;
      position: relative;
       .play-button-pane {
        position: absolute;
        top: 50%;
        left: 50%;
        margin-top: -40px;
        margin-left: -40px;
        >img {
          width: 80px;
        }
      }
  }
}

点击play-button-pane handleItemClick并不会执行,而handleUlClick可以执行,说明事件并没有冒泡到没有添加position的top-pane节点,而冒泡到了添加position:relative的blue-pane节点。具体为啥,有待讨论。

页面刷新beforeRouteEnter钩子函数中的from.path为"/"

一直以为页面刷新和router.push()的方式是一样的,拿到的from.path都是上次路径,使用中发现并不是如此,每次页面刷新,不管是从哪个组件跳转过来的,from.path都是"/"

深度作用选择器 >>>

起因,我想对element的carousel的高度根据屏幕的大小进行调整,但是API只提供了height属性,但是我不想用js拿到屏幕宽度去控制height,我想用media query控制

      <el-carousel trigger="click" height="800px" class="index-carouse pc-index-carouse">
        <el-carousel-item v-for="(item,index) in carouse" :key="index">
          <a :href="item.imgLink">
            <img :src="item.src" alt="">
          </a>
        </el-carousel-item>
      </el-carousel>
      
      <style lang="less" scoped>
        .pc-index-carouse {
          height: 400px;
          .el-carousel__container {
            height: 100% !important;
          }
        }
      </style>

carousel

因为加了scoped 节点有了data-v-277d1ceb属性

.pc-index-carouse .el-carousel__container[data-v-277d1ceb] {
  height: 100% !important;
}

但是classname属性data-v-277d1ceb加在了.el-carousel__container上,应该只加在.pc-index-carouse上这个时候就该深度作用选择器出场了

.pc-index-carouse {
  height: 400px;
  /deep/ .el-carousel__container {
    height: 100% !important;
  }
}

编译后的样式

.pc-index-carouse[data-v-277d1ceb] .el-carousel__container {
  height: 100% !important;
}

这样就通过样式改变了carousel的高度

浅谈vue中style的scoped属性(修改特定Element组件样式的方法)
Scoped CSS

锚点定位报错

vue-router Failed to execute 'querySelector' on 'Document'

原来是因为我每个节点的id都是数字,变成字符串就好了

scrollBehavior (to, from, savedPosition) {
  if (to.hash) {
    return {
      selector: to.hash
    }
  }
}
关于Failed to execute 'querySelectorAll' on 'Document': '#1517905886124' is not a valid selector."

组件自定义事件传参

用的是vant的小程序版的swipe-cell

      if (this.data.asyncClose) {
        this.$emit('close', {
          position: position,
          instance: this
        });
      } else {
        this.swipeMove(0);
      }

父组件里使用swipe-cell

      <van-swipe-cell
        :right-width="65"
        :left-width="65"
        async-close
        :key="item._id"
        v-for="item in list"
        @close="onSwipeClose(arguments,item)"
      >

尝试了各种办法都不能获得两个参数,onSwipeClose.bind(item) 也不行,onSwipeClose返回函数也不行;arguments就是上面emit出去的参数,item就是循环的item。

关于vue自定义事件中,传递参数的一点理解

vuex action 只能传递一个额外参数

传递两个参数都有值
传递两个参数都有值

到action里丢了,只剩dishName

到action里丢了,只剩dishName

所以只能传递一个对象或者数组

Only one parameter works when dispatching actions.

props跟attribute区别

比如:

<blog-post post-title="hello!"></blog-post>

post-title可能是props也可能是attribute

那么什么时候post-title是props什么时候是attribute?

上代码:
App.vue

<template>
  <div id="app">
    <HelloWorld msg="Hello Vue!" v-bind="{ name: 'geek', age: 10 }" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld,
  },
};
</script>

HelloWorld.vue

<template>
  <div class="hello">
    <h3>Installed CLI Plugins</h3>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  mounted() {
    console.info("props:", this.$props); 
    console.info("attr:", this.$attrs);
  },
};
</script>

输出:
image.png
HelloWorld的props中只定义了msg所以props只包含msg,其他的都属于attribute。

改下HelloWorld.vue

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
    name: String,
    age: Number,
  },
  mounted() {
    console.info("props:", this.$props);
    console.info("attr:", this.$attrs);
  },
};
</script>

输出:
image.png

这个时候从父组件传递的所有属性都属于props

attribute的其他作用
attribute会默认将属性加载在根节点,比如第一个例子的name age属性
image.png
如果根节点定义了传递进来的attribute会怎样?会被覆盖(classstyle attribute 会稍微智能一些,即两边的值会被合并起来,从而得到最终的值:)具体参考替换-合并已有的-Attribute
当然也可以在组件设置inheritAttrs:false(2.4.0新增)阻止attribute被设置到组件的根节点,但这个选项不影响 classstyle 绑定


assassin_cike
1.3k 声望74 粉丝

生活不是得过且过