外卖webAPP(四)

一,评价shopRtings页面搭建

在vuex中获取数据,商家评价列表数据

  mounted(){
    this.$store.dispatch('getShopRatings')
  },
  computed:{
    ...mapState(['info', 'ratings'])
  }

填充数据, 根据rateType的标识来来判断是向上的拇指还是向下的拇指

 <div class="recommend">
                <span class="iconfont" :class="rating.rateType===0 ? 'icon-thumb_up' : 'icon-thumb_down'"></span>
                <span class="item" v-for="(item, index) in rating.recommend" :key="index">{{item}}</span>
              </div>

评论信息可以点击滚动,需要在获取数据后(vuex中通知评价组件),创建better-scroll实例

  mounted () {
      this.$store.dispatch('getShopRatings', () => {
        this.$nextTick(() => {
          new BScroll(this.$refs.ratings, {
            click: true
          })
        })
      })
    },
 // 异步获取商家评价列表
  async getShopRatings({commit}, callback) {
    const result = await reqShopRatings()
    if (result.code === 0) {
      const ratings = result.data
      commit(RECEIVE_RATINGS, {ratings})
      // 数据更新了, 通知一下组件
      callback && callback()
    }
  },

关于内容的过滤,全部,满意,不满意,或者是否有内容,这两种条件来过滤评论内容

 全部的数量,满意的数量,不满意的数量

 在ratings数组中每个对象都有个rateType属性,0为满意,1为不满意,在vuex中的getters中计算满意的个数

  positiveSize (state) {
    return state.ratings.reduce((preTotal, rating) => preTotal + (rating.rateType===0?1:0) , 0)
  }

填充模板

...mapGetters(['positiveSize']),
  <div class="ratingselect">
        <div class="rating-type border-1px">
          <span class="block positive" :class="{active: selectType===2}" @click="setSelectType(2)">
            全部<span class="count">{{ratings.length}}</span>
          </span>
          <span class="block positive" :class="{active: selectType===0}" @click="setSelectType(0)">
            满意<span class="count">{{positiveSize}}</span>
          </span>
          <span class="block negative" :class="{active: selectType===1}" @click="setSelectType(1)">
            不满意<span class="count">{{ratings.length-positiveSize}}</span>
          </span>
        </div>
        <div class="switch" :class="{on: onlyShowText}" @click="toggleOnlyShowText">
          <span class="iconfont icon-check_circle"></span>
          <span class="text">只看有内容的评价</span>
        </div>
      </div>

类名on,代表只有内容的评价是否勾选,定义一个变量onlyShowText默然勾选,点击勾选后,标识状态取反

    data () {
      return {
        onlyShowText: true, // 是否只显示有文本的
        selectType: 2 , // 选择的评价类型: 0满意, 1不满意, 2全部
      }
    },
 toggleOnlyShowText () {
        this.onlyShowText = !this.onlyShowText
      }

点击满意,不满意,全部按钮,定义一个变量selectType来标识他们的意思, 选择的评价类型: 0满意, 1不满意, 2全部, 默认全部

active类名动态切换颜色
setSelectType (selectType) {
        this.selectType = selectType
      },

过滤数组,通过两个条件,来过滤筛选之后的数组

 filterRatings () {
        // 得到相关的数据
        const {ratings, onlyShowText, selectType} = this

        // 产生一个过滤新数组
        return ratings.filter(rating => {
          const {rateType, text} = rating
          /*
            条件1:
                selectType: 0/1/2
                rateType: 0/1
                selectType===2 || selectType===rateType
            条件2
                onlyShowText: true/false
                text: 有值/没值
                !onlyShowText || text.length>0
           */
          return (selectType===2 || selectType===rateType) && (!onlyShowText || text.length>0)
        })
      }

填充模板

<div class="rating-wrapper">
        <ul>
          <li class="rating-item" v-for="(rating, index) in filterRatings" :key="index">
            <div class="avatar">
              <img width="28" height="28" :src="rating.avatar">
            </div>
            <div class="content">
              <h1 class="name">{{rating.username}}</h1>

 二,商家shopInfo组件页面搭建

2.1.,从vuex中获取数据info

  mounted(){
    this.$store.dispatch('getShopInfo')
  },

  computed:{
    ...mapState(['info'])
  }

填充数据

 获取服务的标签按钮有三个不同颜色,而获取的数据info.supports数组中,遍历的对象都有type属性,0代表绿色, 1红色,2黄色

我们需要将标签颜色动态渲染,将三个颜色类名定义一个数组,利用type属性来一一对应

 data () {
      return {
        supportClasses: ['activity-green', 'activity-red', 'activity-orange']
      }
    },
   <section class="section">
        <h3 class="section-title">活动与服务</h3>
        <div class="activity">
          <div class="activity-item" v-for="(support, index) in info.supports" :key="index"
              :class="supportClasses[support.type]">
            <span class="content-tag">
              <span class="mini-tag">{{support.name}}</span>
            </span>
            <span class="activity-content">{{support.content}}</span>
          </div>
        </div>
      </section>
2.2,创建商家页面时,要创建better-scroll实例,可以实现滚动
商家实景图片,也要创建better-scroll实例,可以实现滚动
首先数据info,要回来,第二是数据回来最后一次刷新页面,调用this.$nextTick()

方法有两种

第一种,在mouted阶段,dispatch获取到info数据,传一个回调函数,然后vuex中actions发送请求,获取到info数据,在调用这个回调,通知商家页面去做创建scroll的逻辑

 mounted(){
  // 数据回来了,创建bette-scroll
    this.$store.dispatch('getShopInfo',()=>{
        
      this.$nextTick(()=>{
          // info页面滚动
        new BScroll('.shop-info',{
          click : true
        })

         // 获取uldom对象
        const ulNode = this.$refs.picsUl
        const liWidth = 120
        const space = 6
        // 图片数量
        const counts = this.info.pics.length
        // 整个图片盒子长度
        ulNode.style.width =  (liWidth + space) *counts -space  +'px'
        console.log(ulNode.style.width)
         // 商家实景图片滚动,水平滚动
        new BScroll('.pic-wrapper',{
          // click: true,
          scrollX :true
        })

      })
      <section class="section">
        <h3 class="section-title">商家实景</h3>
        <div class="pic-wrapper">
          <ul class="pic-list" ref="picsUl">
            <li class="pic-item" v-for="(pic, index) in info.pics" :key="index">
              <img width="120" height="90" :src="pic"/>
            </li>
          </ul>
        </div>
      </section>
  // 异步获取商家信息
  async getShopInfo({ commit },callback) {
    const result = await reqShopInfo()
    if (result.code === 0) {
      const info = result.data
      commit('RECEIVE_INFO', info)
      callback && callback()
    }
  },

此时实景图片不会滚动,原因是ul父元素的宽度347, 而而li中的图片宽度120,右边距6, 父元素ul不是自适应li的宽度,

解决,我们需要根据li计算ul的宽度, ulNode.style.width =  (liWidth + space) *counts -space  +'px'

方法二,不需要向vuex中的actons传递回调函数
第一次mouted时,获取图片个数报错,需要判断this.info.pics是否有值
 
将创建scroll的逻辑封装成一个函数,在mouted阶段调用, 再次刷新页面,监视数据时在此调用
 

注:1.切换回路由组件,组件生命周期消失了又创建了,会重新执行mounted钩子函数(数据和页面已经都回来了),不会执行watch

2.如果页面刷新了,不会重新执行mounted,需要监听数据变化,执行wacth监听,此时还要先执行this.nextTick()函数,

    mounted () {
    this.$store.dispatch('getShopInfo')
// 如果数据还没有, 直接结束
      if(!this.info.pics) {
        return
      }

      // 数据有了, 可以创建BScroll对象形成滑动
      this._initScroll()
    },

    methods: {
      _initScroll () {
        new BScroll('.shop-info')
        // 动态计算ul的宽度
        const ul = this.$refs.picsUl
        const liWidth = 120
        const space = 6
        const count = this.info.pics.length
        ul.style.width = (liWidth + space) * count -space + 'px'

        new BScroll('.pic-wrapper', {
          scrollX: true // 水平滑动
        })
      }
    },

    watch: {
      info () {// 刷新流程--> 更新数据
        this.$nextTick(() => {
          this._initScroll()
        })
      }
    }

三,搜索search页面搭建

 从vuex中获取搜索商家列表数据,需要传递搜索关键字

当点击提交按钮(阻止form表单自己提交prevent),dispatch到vuex,获取数据

    <form class="search_form" @submit.prevent="search">
      <input type="search" placeholder="请输入商家名称" class="search_input" v-model="keyword">
      <input type="submit" class="search_submit">
    </form>
  methods:{
    search(){
      if(this.keyword.trim()){
        this.$store.dispatch('searchShops',this.keyword )
      }
      
    }
  },

  computed:{
    ...mapState(['searchShops'])
  }

 填充数据

注,点击提交按钮时,当有数据的时候,显示数据,没有数据时,显示很抱歉!无搜索结果

此时,出现一个小bug,当第一次search页面渲染时,没有点击提交按钮,还是显示很抱歉,无搜索结果,需要判断

定义一个标识变量noSearchShops默认false,不显示数据。之后点击提交按钮,需要监视searchShops数据,有新数据,noSearchShops为false,  没有数据为

true
data() {
    return {
      keyword:'',
      imgBaseUrl: 'http://cangdu.org:8001/img/',
      noSearchShops:false
    }
  },
  watch: {
      // 监视searchShop数据
      searchShops (value) {
        if(!value.length) { // 没有数据
          this.noSearchShops = true
        } else {// 有数据
          this.noSearchShops = false
        }
      }
    },

如果router-link被浏览器渲染时a标签,但是如果把它改成li标签,加一个tag属性

  <section class="list" v-if="!noSearchShops">
      <ul class="list_container">
       <!--:to="'/shop?id='+item.id"-->
        <router-link :to="{path:'/shop', query:{id:item.id}}" tag="li"
                     v-for="item in searchShops" :key="item.id" class="list_li">
          <section class="item_left">
            <img :src="imgBaseUrl + item.image_path" class="restaurant_img" style="50px">
          </section>
 
原文地址:https://www.cnblogs.com/fsg6/p/14342601.html