仿去哪儿网webapp(三)

1. 现在安装的脚手架vue-cli是4.4了,vue-router也是4.x,

现在我们安装 vue-router 版本的时候,默认还是安装的 3.x 版本的,由于 vue3 的更新发生很大的变化,所以为了兼容处理,
vue-router 也将发布最新版 4.x 版本了,router当中的一些东西变化很多,参考官网;https://next.router.vuejs.org/zh/api/#router-link-%E7%9A%84-v-slot

比如<router-link tag="">的tag属性删除了,新版的做法

<div class="title">热销推荐</div>
    <ul>
      <!-- <router-link
        :to="`/detali/${recommend.id}`"
        tag="li"
        class="item border-1px-bottom"
        v-for="(recommend, index) in recommendList"
        :key="recommend.id"
      >
        <img :src="recommend.imgUrl" class="item-img" />
        <div class="item-info">
          <p class="item-title">{{ recommend.title }}</p>
          <p class="item-desc">{{ recommend.desc }}</p>
          <button class="item-buttton">查看那详情</button>
        </div>
      </router-link> -->
      <router-link
        :to="`/detail/${recommend.id}`"
        class="item border-1px-bottom"
        v-for="(recommend, index) in recommendList"
        :key="recommend.id"
        v-slot="{ navigate, href }"
         custom
      
      >
        <li @click="navigate" >
          <img :src="recommend.imgUrl" class="item-img" />
          <div class="item-info">
            <p class="item-title">{{ recommend.title }}</p>
            <p class="item-desc">{{ recommend.desc }}</p>
            <button class="item-buttton">查看那详情</button>
          </div>
        </li>
      </router-link>
    </ul>

 2.如果新增了阿里图标数据,那么需要更换以下文件,iconfont文件夹的文件, iconfont.css文件, 另外iconfont.css里头图标url路径需要跟换下

 

 

3.gallary画廊组件

 

 

在banner组件,galllary是子组件,利用vue-awesome-swiper第三方插件做出画廊效果,

此时swiper-pagination底部margin-bottom: -1.1rem, 但是分页器的样式还是没出来,那是应为swiper内部封装的组件中,.swiper-container有个overflow属性
 
需要用深度选择,改写overflow的属性值

 

 

<template>
  <div class="container">
    <div class="wrapper">
      <swiper :options="swiperOptions">
        <swiper-slide>
          <img
            class="gallary-img"
            src="http://img1.qunarzz.com/sight/p0/1804/9a/9ab14695c879723ca3.img.jpg_r_800x800_99bc8e07.jpg"
            alt=""
          />
        </swiper-slide>
        <swiper-slide>
          <img
            class="gallary-img"
            src="http://img1.qunarzz.com/sight/p0/1804/2c/2c9bd88beb228c5ea3.img.jpg_r_800x800_d1a6dc47.jpg"
            alt=""
          />
        </swiper-slide>
        <div class="swiper-pagination" slot="pagination"></div>
      </swiper>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      swiperOptions: {
        pagination: {
          el: ".swiper-pagination",
      //分页器样式 type:
"fraction" }
// pagination: ".swiper-pagination", // type: "fraction" // observeParents: true, // observer: true } }; } }; </script> <style scoped lang="stylus"> .container >>> .swiper-container // 继承副属性 overflow: inherit .container display :flex flex-direction :column justify-content :center z-index :999 position :fixed top:0 left:0 right :0 bottom :0 background:#000 .wrapper height: 0 width: 100% padding-bottom: 53.3% .gallary-img width: 100% .swiper-pagination color: #fff margin-bottom: -1.1rem </style>

 

 3.点击顶部图片,显示画廊组件gallary, 点击画廊组件,影藏画廊组件,

注意,点击顶部图片,显示画廊组件,有个bug,分页器样式没有显示,原因,影藏和显示swiper,需要在自动初始化swiper,加入如下两个属性即可正常了

 

 

gallary子组件

<template>
  <div class="container" @click="handleGallaryClick">
    <div class="wrapper">
      <swiper :options="swiperOptions">
        <swiper-slide>
          <img
            class="gallary-img"
            src="http://img1.qunarzz.com/sight/p0/1804/9a/9ab14695c879723ca3.img.jpg_r_800x800_99bc8e07.jpg"
            alt=""
          />
        </swiper-slide>
        <swiper-slide>
          <img
            class="gallary-img"
            src="http://img1.qunarzz.com/sight/p0/1804/2c/2c9bd88beb228c5ea3.img.jpg_r_800x800_d1a6dc47.jpg"
            alt=""
          />
        </swiper-slide>
        <div class="swiper-pagination" slot="pagination"></div>
      </swiper>
    </div>
  </div>
</template>
 methods:{
    handleGallaryClick(){
      this.$emit('close')
    }
  }
data() {
    return {
      swiperOptions: {
        pagination: {
          el: ".swiper-pagination",
          type: "fraction"
          
        },
        observeParents: true,
        observer: true
       
      }
    };
  },

 

banner父组件

<template>
  <div>
    <div class="banner"  @click="handleBannerClick">
      <img
        class="banner-img"
        src="//img1.qunarzz.com/sight/p0/1804/f1/f15c15c5362d5a8da3.img.jpg_600x330_dc6855d1.jpg"
      />
      <div class="banner-info">
        <!-- 图片介绍 -->
        <div class="banner-tittle">
          大连圣亚海洋世界(AAAA景区)
        </div>
        <div class="banner-number">
          <span class="iconfont  icontupian banner-icon"></span>
          39
        </div>
      </div>
    </div>

    <!-- 画廊组件 -->
    <Gallary v-show="showGallary" @close="handleGallaryClose"></Gallary>
  </div>
</template>

<script>
import Gallary from "common/gallary";
export default {
  data() {
    return {
      showGallary:false
    };
  },

  methods:{
    // 点击轮播图,画廊组件出来
    handleBannerClick () {
      this.showGallary = true
    },
    // 监听画廊组件
    handleGallaryClose(){
      this.showGallary = false
    }
  },

  components: {
    Gallary
  }
};
</script>

 

 4, header组件,给页面全局绑定scroll事件,当滑动大于60px,顶部的景点详情返回图标出现,否则消失,并且有一个opcity渐变效果

注意,全局绑定事件,因为组件被keep-alive包裹,组件切换时激活时,触发activated钩子函数,绑定scroll事件,在切换到其他组件时,触发 deactived钩子函数,解绑scroll事件

 

 

 

 <keep-alive >
      <router-view></router-view>
    </keep-alive>

 

<template>
  <div>
    <router-link class="header-abs" to="/" v-show="showAbs">
      <div class="header-fixed-back iconfont iconfanhui"></div>
    </router-link>

    <router-link
      class="header-fixed"
      to="/"
      v-show="!showAbs"
      :style="opcityStyle"
    >
      <div>
        <div class="header-fixed-back iconfont iconfanhui"></div>
        <span>景点详情</span>
      </div>
    </router-link>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 控制景点详情的显示与影藏
      showAbs: true,
      opcityStyle: {
        opcity: 0
      }
    };
  },

  methods: {
    handleScroll() {
      let top = document.documentElement.scrollTop;
      console.log(top);
      if (top < 60) {
        let opcity = top / 140;
        opcity = opcity > 1 ? 1 : opcity;
        this.opcityStyle = { opcity };
        this.showAbs = true;
      } else {
        this.showAbs = false;
      }
    }
  },

  // mounted() {
  //   // 全局绑定滚动事件,但是只能作用于

  //   window.addEventListener("scroll", this.handleScroll,true);
  // },
  // beforeUnmount() {
  //   // 组件消失,解绑scroll事件
  //   window.removeEventListener("scroll", this.handleScroll,true);
  // },
  // destroyed() {
  //   window.removeEventListener("scroll", this.handleScroll,true);
  // }

  activated() {
    // 全局绑定滚动事件,但是只能作用于
    window.addEventListener("scroll", this.handleScroll);
  },
  deactivated() {
    // 组件消失,解绑scroll事件
    window.removeEventListener("scroll", this.handleScroll);
  }
};
</script>

<style scoped lang="stylus">
@import '~assets/style/varibles.styl'

.header-abs
  position :absolute
  left:.2rem
  top:.2rem
  width:.8rem
  height:.8rem
  line-height :.8rem
  border-radius:.4rem
  text-align:center
  background :rgba(0,0,0,.8)
  opacity :.7
  .header-abs-back
    color:#fff
    font-size:.4rem

.header-fixed
    z-index: 2
    position: fixed
    top: 0
    left: 0
    right: 0
    height: $headerHeight
    line-height: $headerHeight
    text-align: center
    color: #fff
    background: $bgColor
    font-size: .32rem
    .header-fixed-back
      position: absolute
      top: 0
      left: 0
      width: .64rem
      text-align: center
      font-size: .4rem
      color: #fff
</style>

 

 5. vue中递归组件的使用

 

 新建list组件,在detail组件中注册使用,数据传入list组件中, 嵌套数组

<template>
  <div class="container">
    <DetailBanner></DetailBanner>
    <DetailHeader ></DetailHeader>
    <DetailList :List="List" ></DetailList>
  </div>
</template>

<script>
import DetailBanner from "./components/banner";
import DetailHeader from "./components/header";
import DetailList from "./components/list";
export default {
  data() {
    return {
      List: [
        {
          title: "成人票",
          children: [
            {
              title: "成人三馆联票",
              children: [{
                title: "成人三馆联票-某一连锁店销售"
              }]
            }
          ]
        },
        {
          title: "学生票"
        },
        {
          title: "儿童票"
        },
        {
          title: "老年票"
        }
      ]
    };
  },
  components: {
    DetailBanner,
    DetailHeader,
    DetailList
  }

在list组件中,自己调用自己的组件,和name的属性值关联,必须嵌套多层数组

<template>
  <div>
    <div class="item" v-for="(item, index) in List" :key="index">
      <div class="item-title border-1px-bottom">
        <span class="item-title-icon"></span>
        {{ item.title }}
      </div>
      <!-- 递归组件 -->
      <div class="item-children" v-if="item.children">
        <DetailList :List="item.children"></DetailList>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "DetailList",
  data() {
    return {};
  },
  props: {
    List: Array
  }
};
</script>

<style scoped lang="stylus">
@import '~assets/style/mixins.styl'
.item-title
  // position :relative
  line-height :.8rem
  font-size:.32rem
  padding :0 .2rem
  
  .item-title-icon
    // position :absolute
    // left:.06rem
    // top:.06rem
    margin-bottom: -0.05rem;
    display :inline-block
    width:.36rem
    height:.36rem
    background:url(http://s.qunarzz.com/piao/image/touch/sight/detail.png) 0 -.45rem no-repeat
    margin-right:.1rem
    background-size:.4rem 3rem
.item-children
  padding :0 .2rem

</style>

 

 9.关于组件中name对 属性的作用

组件的name属性,1,.递归组件,2.keep-alive组件的exclude属性,3,devtools的vue调试工具的的组件名

组件keep-alive的用法,不保存其他组件的存活,如果切换到detail组件,在mouted阶段发送请求(请求有个parmas参数,唯一的),获取数据,此时需要在keep-alive组件中使用

exclude属性去除detail组件的保留,因为每次切换该组件都会发送新的请求(parmas不同)

  async getDetail() {
      const { data: res } = await axios.get("/api/detail", {
        params: { id: this.$route.params.id }
      });
      // console.log(res)
      if (res.error === 0) {
        this.sightName = res.data.sightName;
        this.bannerImg = res.data.bannerImg;
        this.gallaryImgs = res.data.gallaryImgs;
        this.List = res.data.categoryList;
      }
    }

 

<template>
  <div>
   
    <keep-alive exclude="Detail">
      <router-view></router-view>
    </keep-alive>
    
  </div>
</template>

切换路由组件后,配置路由顶部滑动,在路由总配置

import Vue from "vue";
import VueRouter from "vue-router";
import Home from "views/Home/Home";
import City from "views/city/city";
import Detail from "views/detail/detail";

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    component: Home
  },
  {
    path: "/city",
    component: City
  },
  {
    path: "/detail/:id",
    component: Detail
  }
];

const router = new VueRouter({
  routes,
  scrollBehavior (to, from, savedPosition) {
    return { x: 0, y: 0 }
  }
});

export default router;

 

 利用vue的transition动画封装一个组件fadeAnimation,利用插槽

<template>
  <transition>
    <slot></slot>
  </transition>
</template>

<script>
export default {
  data() {
    return {};
  }
};
</script>

<style scoped lang="stylus">
.v-enter, .v-leave-to
  opacity: 0
.v-enter-active, .v-leave-active
  transition: opacity .5s
</style>

给gallary组件加入动画

<template>
  <div>
    <div class="banner" @click="handleBannerClick">
      <img class="banner-img" :src="bannerImg" />
      <div class="banner-info">
        <!-- 图片介绍 -->
        <div class="banner-tittle">
          {{ sightName }}
        </div>
        <div class="banner-number">
          <span class="iconfont  icontupian banner-icon"></span>
          {{ bannerImgs.length }}
        </div>
      </div>
    </div>
    <FadeAnimation>
      <!-- 画廊组件 -->
      <Gallary
        v-show="showGallary"
        @close="handleGallaryClose"
        :bannerImgs="bannerImgs"
      ></Gallary>
    </FadeAnimation>
  </div>
</template>

<script>
import Gallary from "common/gallary";
import FadeAnimation from "common/FadeAnimation";

 

10.异步组件,路由按需加载,当组件特别大时,整个项目几mb,可以使用

 

 

 

 

 

 

 

 

 

 
posted @ 2021-02-12 20:17  全情海洋  阅读(103)  评论(0编辑  收藏  举报