Vue.js学习记录-13-Vue去哪儿网项目实战:城市列表页开发-Search + List

  • Search:城市选择信息输入检索 (增量式)

    功能点2:用户可以在搜索栏中可输入信息进行城市信息的检索,检索结果以列表形式展现,选定城市后会进行首页的路由跳转。

    功能点2分析:用户故事角度

      作为用户,我想在搜索栏中输入信息后会有结果信息以列表形式展现,并且列表内的内容选择后可以进行页面的跳转,依次来实现城市信息的变更。
    

    具体实现:

    组件data初始化:

      name: 'CitySearch',
      props: {
        cities: Object    父组件City传递的城市信息对象
      },
      data() {
        return {
          keyword: '',   城市名称关键字
          list: [],      存放城市名称信息搜索结果
          timer: null    定时器变量
        }
      }
    

    父组件通过属性进行数据传递:

      <city-search :cities="cities"></city-search>
    

    细节1:搜索栏需要对关键字属性进行双向绑定,并实现监听,当搜索栏中存在关键字会进行下拉列表的展示。

    <template>:v-model实现属性的双向绑定。

      <div class="search">
        <input v-model="keyword" class="search-input" type="text" placeholder="输入城市名或拼音">
      </div>
    

    <script>:对keyword进行响应式侦听,通过定时器来实现在指定时间内进行指定操作。

      watch: {
          keyword() {
            if (this.timer) {
              clearTimeout(this.timer)
            }
            // 如果关键字不存在,清空数组
            if (!this.keyword) {
              this.list = []
              return
            }
            this.timer = setTimeout(() => {
              const result = []
              // 循环至字母表数组
              for (let i in this.cities) {
                // 对每个字母表数组进行循环
                this.cities[i].forEach((value) => {
                  // 针对item的spell、name进行关键字是否为其子串进行判断
                  if (value.spell.indexOf(this.keyword) > -1 ||
                      value.name.indexOf(this.keyword) > -1) {
                    result.push(value)
                  }
                })
      		  // 将结果赋值给list数组
                this.list = result
              }
            }, 100)
          }
      },
    

    细节2:下拉列表的城市信息展示分两种:存在城市信息已列表形式展示,并可以上下滑动/无城市信息显示提示信息。

    1. better-scroll 是一款重点解决移动端(已支持 PC)各种滚动场景需求的插件

      1. 引入better-scroll

        import BScroll from 'better-scroll'

      2. 在组件实例初始化渲染时,利用钩子函数进行better-scroll插件实例初始化

         mounted() {
             // 钩子函数实例化better-scroll
             this.scroll = new BScroll(this.$refs.search)
         }
        
      3. 组件实例依赖绑定DOM元素,采用ref进行DOM元素引用

         <div class="search-content" ref="search" v-show="keyword">
        

        此外该DOM元素的展示与否,依赖于keyword的是否为空

      4. 城市信息列表的布局:<ul>

         <div class="search-content" ref="search" v-show="keyword">
         <ul>
           <li class="search-item border-bottom">
             // 城市信息列表
           </li>
           <li class="search-item border-bottom" v-show="hasNoData">
             没有找到匹配数据
           </li>
         </ul>
        
    2. 无城市信息显示提示信息

      对上述城市信息列表布局中的第二个<li>标签进行分析:hasNoData控制此标签元素的展示与否

      计算属性hasNoData的构建:在模板标签内部不宜出现Js表达式,计算属性实质是对结果数组list长度进行判断。

       computed: {
           hasNoData() {
             return !this.list.length
           }
       },
      

    细节3:对下拉列表的信息进行点击后,携带城市信息实现页面跳转,这里采用Vuex进行数据共享。

    对上述城市信息列表布局中的第一个<li>标签进行分析:

      	<li
              v-for="item of list"
              :key="item.id"
              @click="handleCityClick(item.name)"
              class="search-item border-bottom">
          	{{item.name}}
        	</li>
    

    上述代码中老生长谈的v-for,key的设置,以及插值表达式展示数据value。我们在这里就不提了,着重看一下这个点击事件:handleCityClick

    在这个handleCityClick方法中,将城市名称item.name作为参数传入,结合vuex实现数据共享,也就是我们上篇文章中未提到的组件通过dispatch发起数据调度。

    我们详细的看一下这个handleCityClick方法下文是常规的vuex调用流程,并未使用vuex的map映射概念

      	handleCityClick(city) {
      	  // 组件通过store提供的dispatch方法,向store触发事件并携带参数
    		  this.$store.dispatch('changeCity', city)
            // 组件也可以跳过dispatch方法,直接使用store中的commit方法进行事件的触发
            // this.$store.commit('changeCity', city)
            // 由于采用了keep-alive进行了DOM内容存储,提升体验度这里完成上述业务逻辑后,将搜索区域下拉框关键字置为空,从而控制下拉列表的展示
            this.keyword = ''
            // 点击更改城市信息之后,实现页面跳转
            this.$router.push('/')
          },
    

补充说明:

  1. 常规流程是 vue component 向 Actions 发起 dispatch ,Actions 向 Mutations 进行 commit,但是vue component 也可以直接向 Mutations 进行 commit。

  2. 关于keep-alive,后续会提到,这里是将DOM内容暂存内存中,但是这样会使得搜索框的下拉列表再次进入City界面时仍保持原状,影响体验,于是这里博主添加了this.keyword = ’ ’ ,目的是通过关键字置空从而控制下拉列表的展示。

    未添加前页面下拉列表演示:
    在这里插入图片描述

  3. 方法内部实现路由跳转:实例.$router.push(‘url’) 即可。

  4. 下述组件的说明中,会采用vuex的高级映射特性,简化代码的书写。

  • List:城市列表展示 (增量式)

    组件data初始化:

      name: 'CityList',
        props: {
          cities: Object,
          hot: Array,
          letter: String
      },
    

    父组件通过属性进行数据传递:

    	<city-list :cities="cities" :hot="hotCities" :letter="letter"></city-list>
    

    功能点5:当前城市信息展示区域的选定城市信息展示

    这里我们接着上篇文章中完成一半的功能点5继续往下说明,在这个List组件中,共分为三部分区域:当前城市、热门城市、字母城市列表。

    这三部分的样式设计是一样的,只是区域下的逻辑各有不同。那么针对功能点5进行结尾说明:

    通过vuex实现数据共享,数据源信息存储使用在store模块中的state中,在获取数据方面上我们可以通过vue的高级特性映射拿到mapState。

      import { mapState, mapMutations } from 'vuex'
    

    这里引入mapMutations目的是简化数据交互操作,功能点3上会使用该映射变量。

    通过计算属性进行state数据源信息获取:

      computed: {
        ...mapState({
          currentCity: 'city'
        })
      },
    

    这里的使用方式与上篇文章有所不同,关于变量的命名可以类比ES6语法中,key-value形式中key和value相同时可以简写为一个。

    模板中使用:

      <div class="button">{{this.currentCity}}</div>
    

    功能点3:用户可以在热门城市、字母城市列表中选择城市信息,选定城市后会进行首页的路由跳转。

    整个List列表采用了better-scroll的滚动场景布局,依旧是首先引入better-scroll,通过ref绑定DOM元素实例化BScroll。

      // 引入better-scroll插件
      import BScroll from 'better-scroll'
    
      // ref绑定DOM元素
      <div class="list" ref="wrapper">
    
      // 钩子函数实例化BScroll对象
      // 采用生命周期钩子函数进行DOM引用获取
      mounted() {
        // 创建实例
        this.scroll = new BScroll(this.$refs.wrapper)
      },
    

    该功能点涉及的区域为:热门城市、字母城市列表

    请求返回的数据中分别对应:hot、cities

    <template>:

      <div class="area">
      <div class="title  border-topbottom">热门城市</div>
      <div class="button-list">
        <div class="button-wrapper"
          v-for="item of hot"
          :key="item.id"
          @click="handleCityClick(item.name)">
          <div class="button">{{item.name}}</div>
        </div>
      </div>
      </div>
    

    热门城市区域布局概况:循环遍历接收到的hot数组,利用插值表达式进行数据展示,此外绑定了点击事件handleCityClick

      <!-- 采用ref进行区块滚动DOM结构的标识 -->
      <div class="area" v-for="(item, key) of cities" :key="key" :ref="key">
          <div class="title  border-topbottom">{{key}}</div>
          <div class="item-list">
            <div class="city border-bottom"
              v-for="innerItem of item"
              :key="innerItem.id"
              @click="handleCityClick(innerItem.name)">
              {{innerItem.name}}
              </div>
          </div>
      </div>
    

    字母城市列表布局概况:由于接受的是Object对象,JSON数据采用了[A]-[A1,A2,…]该类型的包装,该区域首先循环遍历外侧数据作为字母表展示,接着对获取到的item进行遍历,遍历出字母列表下的城市列表内容。此外这里也绑定了点击事件handleCityClick

    注:这里的ref="key"绑定了该DOM,是为了实现字母表导航条的随动效果而添加的,随动效果对于该区域来讲是被动的,我将会在Alphabet组件中进行详细说明。

    <script>:

    handleCityClick事件:携带城市信息,用户点击后,通过vuex实现城市信息的变更。

    上文已经提到了:引入了mapMutations变量进行简化数据交互操作。

      methods: {
          handleCityClick(city) {
            // 组件通过store提供的dispatch方法,向store触发事件并携带参数
            // this.$store.dispatch('changeCity', city)
            // 组件也可以跳过dispatch方法,直接使用store中的commit方法进行事件的触发
            // this.$store.commit('changeCity', city)
            // 使用mapMutations进行方法映射
            this.changeCity(city)
            // 点击更改城市信息之后,实现页面跳转
            this.$router.push('/')
          },
          // 映射名称为changeCity的mutation到组件方法中
          ...mapMutations(['changeCity'])
    	},
    
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue.js是一个流行的JavaScript框架,具有轻量级和高度可定制的特点。Element-ui是一个基于Vue.js的组件库,包含了许多用于Web开发的常用组件和工具,应用广泛。 下面是Vue.js和Element-ui的优点: 1. 简单易学 Vue.js和Element-ui具有简单易学的特点,这使它们成为一款流行的选择。在Vue.js中,开发人员可以使用HTML和JavaScript创建组件,开发过程易于理解,而Element-ui提供了丰富的组件和模块,大大加快了开发速度,减少了开发人员的复杂度。 2. 高度可定制 Vue.js和Element-ui框架都具有高度可定制的特点。Vue.js通过数据绑定和组件化,简化了前端开发过程。Element-ui则是一组可定制的UI组件,允许开发人员自由选择和配置UI部件,以适应各种不同需求和应用场景。 3. 强大的功能 Vue.js和Element-ui都拥有强大的功能。通过Vue.js的响应式数据绑定机制和虚拟DOM,能够提高性能和用户体验。Element-ui库中的组件具有各种特性,如自适应、过渡动画和元素样式控制,为开发人员开发高度优化的Web应用提供了强大的支持。 4. 生态系统 Vue.js和Element-ui的优点之一是拥有强大的生态系统和良好的社区支持。社区维护者和开发人员积极分享和更新组件库和知识库,为其他开发人员提供了丰富的资源,减少了学习成本和开发时间。 总的来说,通过使用Vue.js和Element-ui,开发人员可以快速轻松地创建复杂的Web应用程序。这些框架的优点对于开发高度优化的,易于维护的Web应用程序至关重要,而这也是Vue.js和Element-ui在Web开发社区广受欢迎的原因。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小透明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值