vuejs2-4 header.vue组件开发

1 简单图解

2 src/App.vue

<template>
  <div>
    <v-header :seller="seller"></v-header>
    <!--路由切换区域-->
    <div class="tab">
      <div class="tab-item">
        <router-link to="/goods" :seller="seller">商品</router-link>
      </div>
      <div class="tab-item">
        <router-link to="/ratings" :seller="seller">评论</router-link>
      </div>
      <div class="tab-item">
        <router-link to="/seller" :seller="seller">商家</router-link>
      </div>
    </div>
    <!--路由内容区域-->
    <keep-alive>
      <router-view></router-view>
    </keep-alive>
  </div>
</template>
<!--
  'router-link'
      Vuejs2+版本写法 会被解析成<a></a>
      to="/xxx"指向的路由地址(src/main.js配置的路由一致)
  'keep-alive' 组件间切换时保存组件的信息到内存中,切换回来时仍然是之前的状态
  'router-view' 路由渲染视图
  :seller="seller" 父组件向子组件传递自定义名称的数据
-->
<script>
  import header from 'components/header/header.vue'; // 引入header组件
  import {urlParse} from 'common/js/urlParse';
                              // 引入urlParse.js文件 window.loacation.search操作
  const ERR_OK = 0;

  export default {
    data() {
      return {
        seller: {
          id: (() => {
            let queryParam = urlParse(); // 获取地址中的查询字符串
            return queryParam.id;
          })()
        }
      };
    },
    created() {
      let url = '/api/seller?id=' + this.seller.id;
      this.$http.get(url).then((response) => {
        response = response.body;
        if (response.errno === ERR_OK) {
          console.log(response);
          this.seller = Object.assign({}, this.seller, response.data);
        }
      });
    },
    components: { // 注册header组件
      'v-header': header
    }
  };
</script>

<style lang="stylus">
  @import "./common/stylus/mixin.styl"

  .tab
    display: flex
    width: 100%
    height: 40px
    line-height: 40px
    border-1px(rgba(7, 17, 27, 0.1))
  .tab-item
    flex: 1
    text-align: center
    & > a
      display: block
      font-size: 14px
      color: rgb(77, 85, 93)
      &.active
       color: rgb(240, 20, 20)
</style>

3 src/header.vue

<template>
  <div class="header">
    <!-- 商品信息 -->
    <div class="content-wrapper">
      <div class="avatar">
        <img alt="" height="64" width="64" :src="seller.avatar">
      </div>
      <div class="content">

        <div class="title">
          <span class="brand"></span>
          <span class="name">{{seller.name}}</span>
        </div>

        <div class="description">
          {{seller.description}}/{{seller.deliveryTime}}分钟送达
        </div>

        <div v-if="seller.supports" class="support">
          <span class="icon" :class="classMap[seller.supports[0].type]"></span>
          <span class="text">{{seller.supports[0].description}}</span>
        </div>

      </div>
      <div v-if="seller.supports" class="support-count" @click="showDetail(1)">
        <span class="count">{{seller.supports.length}}个</span>
        <i class="icon-keyboard_arrow_right"></i>
      </div>
    </div>
    <!-- 公告 -->
    <div class="bulletin-wrapper" @click="showDetail(1)">
      <span class="bulletin-title"></span><span class="bulletin-text">{{seller.bulletin}}</span>
      <i class="icon-keyboard_arrow_right"></i>
    </div>

    <!--背景图片-->
    <div class="bg">
      <img :src="seller.avatar" width="100%" height="100%" alt="">
    </div>

    <!--公告详情-->
        <!--transition用法变化 css使用变化-->
    <transition name="fade">
      <div v-show="detail_show" class="detail">
      <div class="detail-wrapper clearfix">
        <div class="detail-main">
          <h1 class="name">{{seller.name}}</h1>
          <div class="star-wrapper">
            <star :size="48" :score="seller.score"></star>
          </div>

          <div class="title">
            <div class="line"></div>
            <div class="text">优惠信息</div>
            <div class="line"></div>
          </div>

          <ul class="supports" v-if="seller.supports">
            <li v-for="(item,index) in seller.supports" class="supports-item">
              <span class="icon" :class="classMap[seller.supports[index].type]"></span>
              <span class="text">{{seller.supports[index].description}}</span>
            </li>
          </ul>

          <div class="title">
            <div class="line"></div>
            <div class="text">商家公告</div>
            <div class="line"></div>
          </div>

          <div class="bulletin">{{seller.bulletin}}</div>
        </div>
      </div>
      <div class="detail-close">
        <i class="icon-close" @click="showDetail(0)"></i>
      </div>
    </div>
    </transition>
  </div>
</template>

<script type="text/ecmascript-6">
  import star from 'components/star/star'; // 引入star组件

  export default{
    props: { // 获取父组件传递过来的数据seller
      seller: {
        type: Object
      }
    },
    data() { // Vue 实例的数据对象
      return {
        detail_show: false
      };
    },
    methods: {
      // methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。
      // 方法中的 this 自动绑定为 Vue 实例
      showDetail: function (action) { // 点击显示或隐藏公告详情
        if (action) {
          this.detail_show = true;
        } else {
          this.detail_show = false;
        }
      }
    },
    created() {
      //  实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:
      // 数据观测(data observer),属性和方法的运算, watch/event 事件回调。
      //  然而,挂载阶段还没开始,$el 属性目前不可见。
      this.classMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee'];
    },
    components: {
      // 注册组件 1引入2注册,这样组件才能被使用
      star
    }
  };
</script>

<style lang="stylus" rel="stylesheet/stylus">
  @import "../../common/stylus/mixin"

  .header
    $col = #fff
    $bg = rgba(7,17,27,0.5)
    $pad_top = 24px

    color:$col
    background:$bg
    position:relative
    overflow:hidden

    .content-wrapper
        padding:$pad_top 12px 18px $pad_top
        font-size:0 /*紧贴*/
        position:relative
        .avatar
          display: inline-block
          vertical-align:top
          img
            border-radius:2px
        .content
          margin-left:16px
          display:inline-block
          font-size:14px
          .title
            margin:2px 0 8px 0
            .brand
              display:inline-block
              vertical-align:top /*图片与文字顶部对齐*/
              width:30px
              height:18px
              bg-img("brand") /*按需加载2x1 3x*/
              background-size:30px 17px
              background-repeat:no-repeat
            .name
              margin-left:6px
              font-size:16px
              color:rgb(255,255,255)
              line-height:18px
              font-weight:bold

          .description
            margin-bottom:10px
            font-size:12px;
            color: rgb(255,255,255)
            line-height:12px

          .supports
            .icon
              display:inline-block
              width:12px
              height:12px
              margin-right:4px
              background-size:12px 12px
              background-repeat: no-repeat
              vertical-align:top
              &.decrease
                bg-img("decrease_1")
              &.discount
                bg-img("discount_1")
              &.invoice
                bg-img("invoice_1")
              &.special
                bg-img("special_1")
              &.guarantee
                bg-img("guarantee_1")
            .text
              display:inline-block
              font-size:10px
              color:rgb(255,255,255)
              line-height:12px;
        .support-count
          position:absolute
          right:12px
          bottom:18px
          height:24px
          color:rgb(255,255,255)
          line-height:24px
          background:rgba(0,0,0,.2)
          padding:0px 8px
          text-align:center
          border-radius:12px
          .count
            vertical-align:top
            font-size:10px
          .icon-keyboard_arrow_right
            font-size:10px
            line-height:24px
            margin-left:2px
    .bulletin-wrapper
        height:28px
        line-height:28px
        padding:0 22px 0 12px
        white-space: nowrap
        overflow:hidden
        text-overflow:ellipsis
        position:relative
        background-color:rgba(7,17,27,.2)
        .bulletin-title
          display:inline-block
          height:12px
          width:22px
          bg-img('bulletin')
          background-size:22px 12px
          background-repeat:no-repeat
          vertical-align:top
          margin-top:8px
        .bulletin-text
          font-size:10px
          margin:0 4px
          vertical-align:top
        .icon-keyboard_arrow_right
          position:absolute
          top:8px
          right:12px
          font-size:10px
    .bg
      position:absolute
      left:0
      top:0
      width:100%
      height:100%
      z-index:-1
      filter: blur(10px)

    .detail
      position:fixed
      left:0
      top:0
      z-index:100
      width:100%
      height:100%
      overflow:auto
      opacity: 1
      background: rgba(7, 17, 27, 0.8)
      backdrop-filter: blur(10px)
      &.fade-enter-active,&.fade-leave-active
        transition:all 0.5s
      &.fade-enter,&.fade-leave-active
        opacity:0
        background:rgba(7,17,27,0)
      .detail-wrapper
        min-height:100%
        .detail-main
          margin-top:64px
          padding-bottom:64px
          .name
            font-size:16px
            font-weight:700
            color:rgb(255,255,255)
            line-height:16px
            text-align:center
          .star-wrapper
            margin-top:18px
            padding:2px 0
            text-align:center
          .title
            display:flex
            width:80%
            margin:30px auto 24px auto
            .line
              flex:1
              position:relative
              top: -6px
              border-bottom: 1px solid rgba(255,255,255,.2)
            .text
              padding:0 12px
              font-weight:700
              font-size:14px
          .supports
            width:80%
            margin:0 auto
            .supports-item
              padding:0 12px
              margin-bottom: 12px
              font-size:0
              &:last-child
                margin-bottom:0
              .icon
                display:inline-block
                width:16px
                height:16px
                margin-right:6px
                background-size:16px
                background-repeat:no-repeat
                vertical-align:top
                &.decrease
                  bg-img("decrease_2")
                &.discount
                  bg-img("discount_2")
                &.invoice
                  bg-img("invoice_2")
                &.special
                  bg-img("special_2")
                &.guarantee
                  bg-img("guarantee_2")
              .text
                font-size:12px
                font-weight:200
                color: rgb(255,255,255)
                line-height:16px
          .bulletin
            width:80%
            margin:0 auto
            font-size:12px
            font-weight:200
            color: rgb(255,255,255)
            line-height:24px

      .detail-close
        position: relative
        width:32px
        height:32px
        margin:-64px auto 0 auto
        clear:both
        font-size:32px

</style>

4 使用star组件

<!--并传递两个属性size score给star组件-->
<star :size="48" :score="seller.score"></star> 

5 star组件 src/components/star.vue

<template>
  <div class="star" :class="starType">
    <span v-for="(itemClass,index) in itemClasses" :class="itemClass"
    class="star-item" v-bind:key="itemClass.index"></span>
  </div>
</template>
<!--使用v-for遍历提示加上key区别tra-->
<script type="text/ecmascript-6">
  const LENGTH = 5; // 假设总共有五位
  const CLS_ON = 'on'; //
  const CLS_HALF = 'half';
  const CLS_OFF = 'off';

  export default {
    props: { // 接收header.vue以属性传递过来的数据
      size: {
        type: Number
      },
      score: {
        type: Number
      }
    },
    computed: { // 计算属性
      starType() {
        return 'star-' + this.size;
      },
      itemClasses() {
        let result = [];
        let score = Math.floor(this.score * 2) / 2; // 保证是整数或是x.5的小数 向下取整(4.9、4.1==>4)
        let hasDecimal = score % 1 !== 0;
        let integer = Math.floor(score); // 整数或 x.5小数都取整
        for (let i = 0; i < integer; i++) { // 每位添加全星
          result.push(CLS_ON); // ['on','on']
        };
        if (hasDecimal) { // x.5的小数 末尾有星星的位添加一个半心
          result.push(CLS_HALF); // ['on','on', 'half']
        };
        while (result.length < LENGTH) {  // 剩下的空星位用空星补齐
          result.push(CLS_OFF); // ['on','on', 'half', 'off', 'off', 'off']
        };
        return result;
      }
    }
  };
</script>

<style lang="stylus" rel="stylesheet/stylus">
  @import "../../common/stylus/mixin"

  .star
    font-size: 0
    .star-item
      display: inline-block
      background-repeat: no-repeat
    &.star-48
      .star-item
        width:20px
        height:20px
        margin-right:22px
        background-size: 20px 20px
        &:last-child
          margin-right:0
        &.on
          bg-img('star48_on')
        &.half
          bg-img('star48_half')
        &.off
          bg-img('star48_off')
    &.star-36
     .star-item
        width:15px
        height:15px
        margin-right:8px
        background-size: 15px 15px
        &:last-child
          margin-right:0
        &.on
          bg-img('star36_on')
        &.half
          bg-img('star36_half')
        &.off
          bg-img('star36_off')
    &.star-24
     .star-item
        width:10px
        height:10px
        margin-right:3px
        background-size: 10px 10px
        &:last-child
          margin-right:0
        &.on
          bg-img('star24_on')
        &.half
          bg-img('star24_half')
        &.off
          bg-img('star24_off')

</style>

 

posted @ 2017-04-13 17:00  Jesonhu  阅读(787)  评论(0)    收藏  举报
Top