• 仿美团pc,koa+ssr(三)


    一,通过SSR渲染,将城市服务的数据传给客户端,不是通过异步请求接口获取数据

    store-->新建modules目录--》新建geo.js

    nuxt之vuex中使用nuxtServerInit方法

    官网介绍nuxtServerInit方法

    https://zh.nuxtjs.org/guide/vuex-store/#nuxtserverinit-%E6%96%B9%E6%B3%95

    vuex中模块化使用示例

    挂载vuex中state模块及nuxtServerInit方法, store-->index.js

    在geo.vue组件中获取数据

    <template>
      <div class="m-geo">
        <i class="el-icon-location"/>{{ $store.state.geo.position.city }}
        <nuxt-link
          class="changeCity"
          to="/changeCity">切换城市</nuxt-link>
        [香河 廊坊 天津]
      </div>
    </template>

    二,通过SSR渲染,将商品列表数据传给客户端,不是通过异步请求接口获取数据

    store-->modules-->新建home.js

    const state = () => ({menu: [], hotPlace: []})
    
    const mutations = {
      setMenu(state, val) {
        state.menu = val
      },
      setHotPlace(state, val) {
        state.hotPlace = val
      }
    }
    
    const actions = {
      setMenu: ({
        commit
      }, menu) => {
        commit('setMenu', menu)
      },
      setHotPlace: ({
        commit
      }, hotPlace) => {
        commit('setHotPlace', hotPlace)
      }
    }
    
    export default {namespaced: true, state, mutations, actions}

    store-->index.js,通过ssr服务端获取数据,存储到vuex,让客户端获取数据

    import Vue from 'vue'
    import Vuex from 'vuex'
    import geo from './modules/geo'
    import home from './modules/home'
    
    Vue.use(Vuex)
    
    const store = () => new Vuex.Store({
      modules: {
        geo,
        home
      },
      actions: {
        async nuxtServerInit({
          commit
        }, {req, app}) {
          const {
            status,
            data: {
              province,
              city
            }
          } = await app.$axios.get('/geo/getPosition')
          // 提交到geo.js文件中的setPosition函数,将当前城市位置{city,province}保存在vuex中
          commit('geo/setPosition',status===200?{city,province}:{city:'',province:''})
          const {status:status2,data:{menu}}=await app.$axios.get('geo/menu')
          //提交到home.js文件中的setMenu函数,将menu商品分类数据保存在vuex中
          commit('home/setMenu',status2===200?menu:[])
          const {status:status3,data:{result}}=await app.$axios.get('/search/hotPlace',{
            params:{
              city:app.store.state.geo.position.city.replace('','')
            }
          })
          //提交到home.js文件中的setHotPlace函数,将result热门景点数据保存在vuex中
          commit('home/setHotPlace',status3===200?result:[])
        }
      }
    })
    
    export default store

    menu.vue组件中,获取数据

    <template>
      <div class="m-menu">
        <!-- 左侧商品列表 -->
        <dl
          class="nav"
          @mouseleave="mouseleave">
          <dt>全部分类</dt>
          <dd
            v-for="(item,idx) in $store.state.home.menu"
            :key="idx"
            @mouseenter="enter">
            <i :class="item.type"/>{{ item.name }}<span class="arrow"/>
          </dd>
        </dl>
        <!-- 右侧商品列表 -->
        <div
          v-if="kind"
          class="detail"
          @mouseenter="sover"
          @mouseleave="sout">
          <template
            v-for="(item,idx) in curdetail.child">
            <h4 :key="idx">{{ item.title }}</h4>
            <span
              v-for="v in item.child"
              :key="v">{{ v }}</span>
          </template>
        </div>
      </div>
    </template>
      computed:{
        curdetail:function(){
          return this.$store.state.home.menu.filter(item => item.type===this.kind)[0]
        }
      },

    三,点击输入框,输入关键字,发送请求,获取与输入关键词有关的数据,以及,热门景点数据填充

     

    在searchbar.vue组件中

    <template>
      <div class="search-panel">
        <el-row class="m-header-searchbar">
          <el-col
            :span="3"
            class="left">
            <img
              src="//s0.meituan.net/bs/fe-web-meituan/e5eeaef/img/logo.png"
              alt="美团">
          </el-col>
          <el-col
            :span="15"
            class="center">
            <div class="wrapper">
              <el-input
                v-model="search"
                placeholder="搜索商家或地点"
                @focus="focus"
                @blur="blur"
                @input="input"/>
              <button class="el-button el-button--primary"><i class="el-icon-search"/></button>
              <dl
                v-if="isHotPlace"
                class="hotPlace">
                <dt>热门搜索</dt>
                <dd
                  v-for="(item,idx) in $store.state.home.hotPlace.slice(0,5)"
                  :key="idx">
                  <a :href="'/products?keyword='+encodeURIComponent(item.name)">{{ item.name }}</a>
                </dd>
              </dl>
              <dl
                v-if="isSearchList"
                class="searchList">
                <dd
                  v-for="(item,idx) in searchList"
                  :key="idx">
                  <a :href="'/products?keyword='+encodeURIComponent(item.name)">{{ item.name }}</a>
                </dd>
              </dl>
            </div>
            <p class="suggest">
              <a
                v-for="(item,idx) in $store.state.home.hotPlace.slice(0,5)"
                :key="idx"
                :href="'/products?keyword='+encodeURIComponent(item.name)">{{ item.name }}</a>
            </p>
            <ul class="nav">
              <li><nuxt-link
                to="/"
                class="takeout">美团外卖</nuxt-link></li>
              <li><nuxt-link
                to="/"
                class="movie">猫眼电影</nuxt-link></li>
              <li><nuxt-link
                to="/"
                class="hotel">美团酒店</nuxt-link></li>
              <li><nuxt-link
                to="/"
                class="apartment">民宿/公寓</nuxt-link></li>
              <li><nuxt-link
                to="/"
                class="business">商家入驻</nuxt-link></li>
            </ul>
          </el-col>
          <el-col
            :span="6"
            class="right">
            <ul class="security">
              <li><i class="refund"/><p class="txt">随时退</p></li>
              <li><i class="single"/><p class="txt">不满意免单</p></li>
              <li><i class="overdue"/><p class="txt">过期退</p></li>
            </ul>
          </el-col>
        </el-row>
      </div>
    </template>
    
    <script>
    import _ from 'lodash'
    export default {
      data(){
        return {
          search:'',
          isFocus:false,
          hotPlace:[],
          searchList:[]
        }
      },
      computed:{
        isHotPlace:function(){
          return this.isFocus&&!this.search
        },
        isSearchList:function(){
          return this.isFocus&&this.search
        }
      },
      methods:{
        focus:function(){
          this.isFocus=true
        },
        blur:function(){
          let self=this;
          setTimeout(function(){
            self.isFocus=false
          },200)
        },
        // 做个防抖延时函数,引入lodash
        input:_.debounce(async function(){
          let self=this;
          
          let city=self.$store.state.geo.position.city.replace('','')
          self.searchList=[]
          let {status,data:{top}}=await self.$axios.get('/search/top',{
            params:{
              input:self.search,
              city
            }
          })
          // 截取十条数据
          self.searchList=top.slice(0,10)
        },300)
      }
    }
    </script>
    
    <style lang="css">
    </style>

    四,移入不同的标签,展示不同的图片数据

    在artistic.vue组件中

    <template>
      <section class="m-istyle">
        <dl @mouseover="over">
          <dt>有格调</dt>
          <dd
            :class="{active:kind==='all'}"
            kind="all"
            keyword="景点">全部</dd>
          <dd
            :class="{active:kind==='part'}"
            kind="part"
            keyword="美食">约会聚餐</dd>
          <dd
            :class="{active:kind==='spa'}"
            kind="spa"
            keyword="丽人">丽人SPA</dd>
          <dd
            :class="{active:kind==='movie'}"
            kind="movie"
            keyword="电影">电影演出</dd>
          <dd
            :class="{active:kind==='travel'}"
            kind="travel"
            keyword="旅游">品质出游</dd>
        </dl>
        <ul class="ibody">
          <li
            v-for="item in cur"
            :key="item.title">
            <el-card
              :body-style="{ padding: '0px' }"
              shadow="never">
              <img
                :src="item.img"
                class="image">
              <ul class="cbody">
                <li class="title">{{ item.title }}</li>
                <li class="pos"><span>{{ item.pos }}</span></li>
                <li class="price">¥<em>{{ item.price }}</em><span>/起</span></li>
              </ul>
            </el-card>
          </li>
        </ul>
      </section>
    </template>
    <script>
    export default {
      data: () => {
        return {
          // 默认属性
          kind: 'all',
          list: {
            // 通过kind属性获取对应的数据
            all: [],
            part: [],
            spa: [],
            movie: [],
            travel: []
          }
        }
      },
      computed: {
        // 计算不同类型数据
        cur: function () {
          return this.list[this.kind]
        }
      },
      // 刚加载页面,加载默认的数据
      async mounted(){
        let self=this;
        let {status,data:{count,pois}}=await self.$axios.get('/search/resultsByKeywords',{
          params:{
            // 默认
            keyword:'景点',
            city:self.$store.state.geo.position.city
          }
        })
        if(status===200&&count>0){
          let r= pois.filter(item=>item.photos.length).map(item=>{
            return {
              title:item.name,
              pos:item.type.split(';')[0],
              price:item.biz_ext.cost||'暂无',
              img:item.photos[0].url,
              url:'//abc.com'
            }
          })
          self.list[self.kind]=r.slice(0,9)
        }else{
          self.list[self.kind]=[]
        }
      },
      methods: {
        // 移入事件
        over: async function (e) {
          let dom = e.target
          let tag = dom.tagName.toLowerCase()
          let self = this
          if (tag === 'dd') {
            // 获取自定义的属性,请求参数
            this.kind = dom.getAttribute('kind')
            let keyword = dom.getAttribute('keyword')
            let {status,data:{count,pois}}=await self.$axios.get('/search/resultsByKeywords',{
              params:{
                keyword,
                city:self.$store.state.geo.position.city
              }
            })
            if(status===200&&count>0){
              // 过滤出有图片的数据,并且数据库的字段和前端的字段需要映射(前端字段和数据库字段不一致)
              let r= pois.filter(item=>item.photos.length).map(item=>{
                return {
                  title:item.name,
                  pos:item.type.split(';')[0],
                  price:item.biz_ext.cost||'暂无',
                  img:item.photos[0].url,
                  url:'//abc.com'
                }
              })
              // 截取9条数据,通过kind属性获取对应的数据
              self.list[self.kind]=r.slice(0,9)
            }else{
              self.list[self.kind]=[]
            }
          }
        }
      },
    
    }
    </script>
    <style lang="scss">
        @import "@/assets/css/index/artistic.scss";
    </style>
  • 相关阅读:
    POJ 1330 Nearest Common Ancestors (LCA,dfs+ST在线算法)
    BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊 (动态树LCT)
    HDU 4010 Query on The Trees (动态树)
    SPOJ 375. Query on a tree (动态树)
    BZOJ 2049: [Sdoi2008]Cave 洞穴勘测 (动态树入门)
    HDU 3726 Graph and Queries (离线处理+splay tree)
    POJ 3580 SuperMemo (splay tree)
    Android中visibility属性VISIBLE、INVISIBLE、GONE的区别
    mysql如何在一张表中插入一万条数据?(用存储过程解决)
    Gradle Build速度加快方法汇总
  • 原文地址:https://www.cnblogs.com/fsg6/p/14428907.html
Copyright © 2020-2023  润新知