阅读 320

vue头标签的再认识,涵盖样式模块化

好好学习

rem以及自定义vue头标签

原来我以为的头标签就只是原装的<head></head>,然后在里面balabala写,结果今天才知道,它也是可以“我想怎么样就怎么样”的~
来左边跟我一起放个logo,来右边放一个编辑~

效果初览

ps:没错,这个草率的ele.me就是说传说中的logo,对了,单击<箭头会回退哟!

先来认识rem

为了适应不同的显示器,我们用px单位可想而知是不够的。所以我们用rem做到所有设备自适应。rem是css的相对单位。

在vue单页项目中,如何做到设备自适应?

肯定是不能写死的,用动态,如:16rem=100%,这个就是动态宽度的100%。
16其实就是引入了栅格系统,将一行分为16列,比如设为8:8,它其实就是两列左右对等布局,4:4:4其实就是三列式布局。那么要怎么做呢?要对html的fontSize进行一个计算。

创建一个vue项目ele

新建的项目只需要勾选babel和router即可。

先从rem开始

在main.js中,先导入我们要的rem。
import './config/rem'
大型项目中组件如何兼容? rem是第一项要考虑的。

项目配置目录cofig

src/config/rem.js,在这里手动计算rem。

(function(doc, win){
    var docEl = doc.documentElement, //获取html
    // docEl.style.fontSize = '23.5px'; //先写死一个值测试一下
})(document, window) // 建一个闭包, 立即执行函数,传两个实参
复制代码
  1. 闭包区域,把document和window传进去。闭包里面定义的变量,不会污染外界。我们在闭包里面动态计算我们html的fondSize。
  2. 利用width/16,使用栅格能力(css中的等比例计算)。
  3. 写一个专门计算rem的函数recalc:
(function(doc, win){
    var docEl = doc.documentElement, //获取html
    
    recalc = function() {
        // 设备无差异计算出  16rem = 100% width
        var clientWidth = docEl.clientWidth; //html的整个窗口的宽度
         // console.log(clientWidth);

        if (!clientWidth) return;
        docEl.style.fontSize = 20 * clientWidth/320 + 'px';
        // console.log(clientWidth);
      };
      doc.addEventListener('DOMContentLoaded', recalc, false);
      
    // docEl.style.fontSize = '23.5px'; //先写死一个值测试一下
})(document, window) // 建一个闭包, 立即执行函数,传两个实参
复制代码
  1. 来解释一下doc.addEventListener('DOMContentLoaded', recalc, false); 监听DOMContentLoaded事件。在vue里面也有生命周期,DOMContentLoaded事件比loaded事件先发生,因为loaded要等到所有图片都加载完,整个页面都加载完了才触发,而DOMContentLoaded事件只要DOM结构加载完了(html结构)加载完成了,就会触发。此时我们就去计算fontSize的大小。,当它触发DOMContentLoaded事件的时候,我们去调用recalc函数,第三个参数为false。
    关于第三个参数false:
    false是事件监听中,到底是从外到内(捕获),还是从内到外(冒泡)的选择。为false是内层向外层执行(冒泡),为true是由外向内执行(捕获)。
  2. 为什么是20 * clientWidth/320呢?
    首先,通过clientWidth计算,整个宽度分成320份,再乘以20,刚好是16,也就是将clientWidth分成十六份。而对于320,是有可能在最初的设计稿中,是320的设计稿,(现在一般都是750的,它的1/2是375),之前的是640的,就是两倍于宽度,所以就是320,我们这里用老的设计稿的(640)。然后再凑出16。所以这里是20。 用一个盒子来检验一下效果:
<div style="width:16rem;height:2rem;background-color:red;"></div>
复制代码

当设备变化的时候,如何实现自适应呢?

比如设备可能由纵向,变成横向,还有可能屏幕尺寸发生改变。那怎么做呢?

(function(doc, win){
    var docEl = doc.documentElement, //获取html
    // 是否换了方向,横屏? 调整窗口宽度->resize事件
      resizeEvt = 'orientationchange' in win ? 'orientationchange': 'resize',
    
    recalc = function() {
        // 设备无差异计算出  16rem = 100% width
        var clientWidth = docEl.clientWidth; //html的整个窗口的宽度
         // console.log(clientWidth);

        if (!clientWidth) return;
        docEl.style.fontSize = 20 * clientWidth/320 + 'px';
        // console.log(clientWidth);
        // ?设备可能由纵向变模着拿 尺寸发生变化
        win.addEventListener(resizeEvt, recalc, false);
      };
      doc.addEventListener('DOMContentLoaded', recalc, false);
      
    // docEl.style.fontSize = '23.5px'; //先写死一个值测试一下
})(document, window) // 建一个闭包, 立即执行函数,传两个实参
复制代码
  1. window对象中如果发生orientationchange窗口改变事件(横屏或竖屏),就返回orientationchange,否则返回resize事件(调整窗口宽度时)。

接下来看header组件

来到App.vue,先定义一个组件:

export default {
  components: { //组件声明
    // 不能与标签名字header重合,怎么解决?
    // head-top是在页面上的标签名  Header是类名
    "head-top": Header
  }  
}
复制代码

将我们自定义的header封装:
import Header from './components/header/header'; //封装这个组件

构建components/header/header组件

在components下建一个header/header.vue 下面先展示一个错误的:

<template>
    <header id="head_top">
        header
    </header>
</template>
复制代码
  1. 我们的标签名字,不能跟html5的标签名字一样,因为会先解析html的标签。当名字不一样时,解析时它就不会去找html标签,而是去组件声明里面找组件,所以写成"head-top": Header,其中"head-top"就是我们在页面上写的占位符(标签名)。而Header其实是类名。
  2. 所以修改一下:
<template>
    <head-top id="编辑地址">
        header
    </head-top>
</template>
复制代码

给组件传递一个标题和logo

<head-top headTitle="编辑地址">
      <span class="head_logo" >ele.me</span>
</head-top>
复制代码

进行header的封装

来到header.vue

  1. 先打理标题参数。
<script>
export default {
  props: ['headTitle']
}
</script>
复制代码
  1. 将logo放置在左边。使用span和slot,在组件之间插槽插入。 App.vue中先放好了span,现在直接在header.vue中:
<header id="head_top">
    <!-- slot在{{headTitle}}前面,所以就插好了 用一个name -->
    <slot name="logo"></slot>
    <!-- section是一个区块 这里写了两个类名 -->
    <!--用户传了headTitle我们才输出,否则不输出-->
    <section class="title_head ellipsis" v-if="headTitle">
      <span class="title_text">
        {{headTitle}}
      </span>
    </section>
</header>
复制代码
  1. 写点样式。 header.vue中:
<style lang="styl" scoped>
@import "../../style/mixin.styl";
/* $blue是定义的stylus变量 
position fixed固定定位*/
#head_top
  background-color $blue
  position fixed
  z-index 100
  left 0
  top 0
  wh(100%, 1.95rem)
  .title_head
    center()
    width 50%
    color #fff
    text-align center
    .title_text
      sc(0.8rem, #fff)
      text-align center
      font-weight bold
  .head_goback
    left 0.4rem
    wh(0.6rem, 1rem)
    line-height 2.2rem
    margin-left 0.4rem 

</style>
复制代码

我们用的是stylus,所以记得先install一下,在终端中yarn add stylus stylus-loader
import导入样式文件时一定一定记得加分号!
4. 在这里面我们复用了样式,写在了mixin.styl文件中,注意看哦!

<!--定义了一个超级变量blue-->
$blue = #3190e8;

wh($width, $height)
  width $width
  height $height

center()
  top 50%
  left 50%
  position absolute
  transform translate(-50%, -50%)

sc($size, $color)
  font-size $size
  color $color

ct()
  top 50%
  position absolute
  transform translateY(-50%)
复制代码

再加上右边的编辑

同样用slot方式插在标题右边:

<section class="title_head ellipsis" v-if="headTitle">
      <span class="title_text">
        {{headTitle}}
      </span>
</section>
<slot name="edit"></slot>
复制代码

  1. 解释一下slot,因为我们插入的slot比较多,放左边还是右边就容易被夹在一起。那么如何区分呢?给slot加上name就好啦~(具名插槽) 然后<span>中就写成这样: App.vue
<head-top head-title="编辑地址" go-back="true">
      <span class="head_logo" slot="logo">ele.me</span>
      <!-- slot的name来区分编辑和logo的不同位置 -->
      <span class="edit" slot="edit">编辑</span>
</head-top>
复制代码

最后加上一个返回上一步

header.vue中

<!-- section是一个区块 -->
    <section class="head_goback" v-if="goBack" @click="$router.go(-1)">
      <svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" version="1.1">
        <polyline points="12,18 4,9 12,0" style="fill:none;stroke:rgb(255,255,255);stroke-width:2"/>
      </svg>
 </section>
复制代码

就是这个小箭头。
其中@click="$router.go(-1)"可以实现单击后返回上一层。

这里是结尾

简单的一个关于rem,和header,以及css模块化的小例子就分享到这了,喜欢的点个start~
github戳这里