Vue移动端项目(二)

本文详细介绍了使用Vue.js开发移动端项目的部分关键功能,包括首页频道编辑和文章搜索。在频道编辑中,涉及弹出层处理、频道组件创建、布局设计、频道数据的增删改查及持久化。文章搜索功能涵盖搜索联想建议、搜索结果展示、历史记录管理和页面状态处理。此外,还探讨了处理大数字问题和JSON数据解析策略。
摘要由CSDN通过智能技术生成

五、首页—频道编辑

处理页面弹出层

Vant 中内置了 Popup 弹出层 组件。

1、在 data中添加一个数据用来控制弹层的显示和隐藏

data () {
   
  return {
   
    ...
    isChannelEditShow: true // 这里我们先设置为 true 就能看到弹窗的页面了
  }
}

2、然后在首页模板中的频道列表后面添加弹出层组件

<!-- 频道编辑 -->
<van-popup
  class="edit-channel-popup"
  v-model="isEditChannelShow"
  position="bottom"
  :style="{ height: '100%' }"
  closeable
  close-icon-position="top-left"
>内容</van-popup>
<!-- /频道编辑 -->
.edit-channel-popup {
  padding-top: 100px;
	box-sizing: border-box;
}

测试查看结果。

创建频道编辑组件

1、创建 views/home/components/channel-edit.vue

<template>
  <div class="channel-edit">频道编辑</div>
</template>

<script>
export default {
     
  name: 'ChannelEdit',
  components: {
     },
  props: {
     },
  data () {
     
    return {
     }
  },
  computed: {
     },
  watch: {
     },
  created () {
     },
  mounted () {
     },
  methods: {
     }
}
</script>

<style scoped lang="less"></style>

2、在首页中加载注册

import ChannelEdit from './components/channel-edit'
export default {
   
  ...
  components: {
   
    ...
    ChannelEdit
  }
}

3、在弹出层中使用频道编辑组件

<!-- 频道编辑 -->
<van-popup
  v-model="isChannelEditShow"
  position="bottom"
  closeable
  close-icon-position="top-left"
  :style="{ height: '100%' }"
>
+  <channel-edit />
</van-popup>
<!-- /频道编辑 -->

页面布局

<template>
  <div class="channel-edit">
    <van-cell title="我的频道" :border="false">
      <van-button
        size="mini"
        round
        type="danger"
        plain
      >编辑</van-button>
    </van-cell>
    <van-grid :gutter="10">
      <van-grid-item
        class="channel-item"
        v-for="value in 8"
        :key="value"
        text="文字"
      />
    </van-grid>
    <van-cell title="频道推荐" :border="false"></van-cell>
    <van-grid :gutter="10">
      <van-grid-item
        class="channel-item"
        v-for="value in 8"
        :key="value"
        text="文字"
      />
    </van-grid>
  </div>
</template>

<script>
export default {
     
  name: 'ChannelEdit',
  components: {
     },
  props: {
     },
  data () {
     
    return {
     }
  },
  computed: {
     },
  watch: {
     },
  created () {
     },
  mounted () {
     },
  methods: {
     }
}
</script>

<style scoped lang="less">
.channel-edit {
     
  .channel-item {
     
    height: 86px;
    /deep/ .van-grid-item__content {
     
      background-color: #f5f5f6;
      .van-grid-item__text {
     
        color: #222;
        font-size: 28px;
      }
    }
  }
}
</style>

展示我的频道

1、在父组件中把 channels 传递给频道编辑组件

image-20200316002816033

2、在频道编辑组件中声明接收父组件的 userChannels 频道列表数据并遍历展示

image-20200316002911027 image-20200316002958971

展示推荐频道列表

1571040968593

没有用来获取推荐频道的数据接口,但是我们有获取所有频道列表的数据接口。

所以:所有频道列表 - 我的频道 = 剩余推荐的频道

实现过程所以一共分为两大步:

  • 获取所有频道
  • 基于所有频道和我的频道计算获取剩余的推荐频道

获取所有频道

1、封装数据接口

/**
 * 获取所有频道
 */
export const getAllChannels = () => {
   
  return request({
   
    method: 'GET',
    url: '/app/v1_0/channels'
  })
}

2、在编辑频道组件中请求获取所有频道数据

image-20200316021948407 image-20200316022017473

3、在调试工具中测试是否有拿到数据

处理展示推荐频道

思路:所有频道 - 用户频道 = 推荐频道

1、封装计算属性筛选数据

image-20200316022123370
  • 遍历所有频道
  • 对每一个频道都判断:该频道是否属于我的频道
  • 如果不属于我的频道,则收集起来
  • 直到遍历结束,剩下来就是那些剩余的推荐频道

2、模板绑定

image-20200316022153646

添加频道

频道管理-添加频道

思路:

  • 给推荐频道列表中每一项注册点击事件
  • 获取点击的频道项
  • 将频道项添加到我的频道中
  • 将当前点击的频道项从推荐频道中移除
    • 不需要删除,因为我们获取数据使用的是计算属性,当我频道发生改变,计算属性重新求值了

1、给推荐频道中的频道注册点击事件

image-20200316030501261

2、在添加频道事件处理函数中

image-20200316030518012

然后你会神奇的发现点击的那个推荐频道跑到我的频道中了,我们并没有去手动的删除点击的这个推荐频道,但是它没了!主要是因为推荐频道是通过一个计算属性获取的,计算属性中使用了 channels(我的频道)数据,所以只要我的频道中的数据发生变化,那么计算属性就会重新运算获取最新的数据。

编辑频道

思路:

  • 给我的频道中的频道项注册点击事件
  • 在事件处理函数中
    • 如果是编辑状态,则执行删除频道操作
    • 如果是非编辑状态,则执行切换频道操作

处理编辑状态

1、在 data 中添加数据用来控制编辑状态的显示

image-20200316033317098

2、在我的频道项中添加删除图标

image-20200316033121847 image-20200316033200148

3、处理点击编辑按钮

image-20200316033239687

切换频道

功能需求:在非编辑器状态下切换频道。

1、给我的频道项注册点击事件

image-20200316040309812

2、处理函数

image-20200316040344551

3、在父组件中监听处理自定义事件

image-20200316040428331

让激活频道高亮

思路:

  • 将首页中的激活的标签索引传递给频道编辑组件
  • 在频道编辑组件中遍历我的频道列表的时候判断遍历项的索引是否等于激活的频道标签索引,如果一样则作用一个高亮的 CSS 类名

1、将首页组件中的 active 传递到频道编辑组件中

image-20200316004637299

2、在频道编辑组件中声明 props 接收

image-20200316004657340

3、判断遍历项,如果 遍历项索引 === active,则给这个频道项设置高亮样式

image-20200316004830847 image-20200316004847629

删除频道

功能需求:在编辑状态下删除频道。

image-20200316042008623

频道数据持久化

业务分析

频道编辑这个功能,无论用户是否登录用户都可以使用。

不登录也能使用

  • 数据存储在本地
  • 不支持同步功能

登录也能使用

  • 数据存储在线上后台服务器
  • 更换不同的设备可以同步数据

添加频道

思路:

  • 如果未登录,则存储到本地
  • 如果已登录,则存储到线上
    • 找到数据接口
    • 封装请求方法
    • 请求调用

1、封装添加频道的请求方法

/**
 * 添加用户频道
 */
export const addUserChannel = channels => {
   
  return request({
   
    method: 'PATCH',
    url: '/app/v1_0/user/channels',
    data: {
   
      channels
    }
  })
}

2、修改添加频道的处理逻辑

async onAddChannel (channel) {
   
  try {
   
    this.userChannels.push(channel)
    if (this.user) {
   
      // 已登录,数据存储到线上
      await addUserChannel([{
   
        id: channel.id, // 频道 id
        seq: this.userChannels.length // 频道的 序号
      }])
    } else {
   
      // 未登录,数据存储到本地
      setItem('channels', this.userChannels)
    }
  } catch (err) {
   
    console.log(err)
    this.$toast('添加频道失败')
  }
},

删除频道

思路:

  • 如果未登录,则存储到本地
  • 如果已登录,则存储到线上
    • 找到数据接口
    • 封装请求方法
    • 请求调用

1、封装删除用户频道请求方法

/**
 * 删除用户频道
 */
export const deleteUserChannel = channelId => {
   
  return request({
   
    method: 'DELETE',
    url: `/app/v1_0/user/channels/${
     channelId}`
  })
}

2、修改删除频道的处理逻辑

image-20200316051028617
async deleteChannel (channel) {
   
  try {
   
    if (this.user) {
   
      // 已登录,将数据存储到线上
      await deleteUserChannel(channel.id)
    } else {
   
      // 未登录,将数据存储到本地
      setItem('channles', this.userChannels)
    }
  } catch (err) {
   
    console.log(err)
    this.$toast('删除频道失败,请稍后重试')
  }
}

正确的获取首页频道列表数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-At2CxmGV-1659971681941)(assets/首页-获取频道列表.png)]

提示:获取登录用户的频道列表和获取默认推荐的频道列表是同一个数据接口。后端会根据接口中的 token 来判定返回数据。

async loadChannels () {
   
  try {
   
    let channels = []
    if (this.user) {
   
      // 已登录,请求获取线上的频道数据
      const {
    data } = await getChannels()
      channels = data.data.channels
    } else {
   
      // 未登录
      const localChannels = getItem('channels')
      if (localChannels) {
   
        // 有本地频道数据,则使用
        channels = localChannels
      } else {
   
        // 没有本地频道数据,则请求获取默认推荐的频道列表
        const {
    data } = await getChannels()
        channels = data.data.channels
      }
    }

    // 将数据更新到组件中
    this.channels = channels
  } catch (err) {
   
    console.log(err)
    this.$toast('数据获取失败')
  }
},

六、文章搜索

创建组件并配置路由

1、创建 src/views/search/index.vue

<template>
  <div class="search-container">搜索页面</div>
</template>

<script>
  export default {
     
    name: "SearchPage",
    components: {
     },
    props: {
     },
    data() {
     
      return {
     };
    },
    computed: {
     },
    watch: {
     },
    created() {
     },
    methods: {
     }
  };
</script>

<style scoped></style>

2、然后把搜索页面的路由配置到根组件路由(一级路由)

{
   
  path: '/search',
  omponent: Search
}

最后访问 /search 测试。

页面布局

1、创建 src/views/search/components/search-history.vue

<template>
  <div class="search-history">
    <van-cell title="搜索历史">
      <span>全部删除</span>
      <span>完成</span>
      <van-icon name="delete" />
    </van-cell>
    <van-cell title="hello">
      <van-icon name="close" />
    </van-cell>
    <van-cell title="hello">
      <van-icon name="close" />
    </van-cell>
    <van-cell title="hello">
      <van-icon name="close" />
    </van-cell>
    <van-cell title="hello">
      <van-icon name="close" />
    </van-cell>
  </div>
</template>

<script>
export default {
     
  name: 'SearchHistory',
  components: {
     },
  props: {
     },
  data () {
     
    return {
     }
  },
  computed: {
     },
  watch: {
     },
  created () {
     },
  mounted () {
     },
  methods: {
     }
}
</script>

<style scoped lang="less"></style>

2、创建 src/views/search/components/search-suggestion.vue

<template>
  <div class="search-suggestion">
    <van-cell title="黑马程序员..." icon="search"></van-cell>
    <van-cell title="黑马程序员..." icon="search"></van-cell>
    <van-cell title="黑马程序员..." icon="search"></van-cell>
    <van-cell title="黑马程序员..." icon="search"></van-cell>
    <van-cell title="黑马程序员..." icon="search"></van-cell>
  </div>
</template>

<script>
export default {
     
  name: 'SearchSuggestion',
  components: {
     },
  props: {
     },
  data () {
     
    return {
     }
  },
  computed: {
     },
  watch: {
     },
  created () {
     },
  mounted () {
     },
  methods: {
     }
}
</script>

<style scoped lang="less"></style>

3、创建 src/views/search/components/search-result.vue

<template>
  <div class="search-result">
    <van-list
      v-model="loading"
      :finished="finished"
      finished-text="没有更多了"
      @load="onLoad"
    >
      <van-cell v-for="item in list" :key="item" :title="item" />
    </van-list>
  </div>
</template>

<script>
export default {
     
  name: 'SearchResult',
  components: {
     },
  props: {
     },
  data () {
     
    return {
     
      list: [],
      loading: false,
      finished: false
    }
  },
  computed: {
     },
  watch: {
     },
  created () {
     },
  mounted () {
     },
  methods: {
     
    onLoad () {
     
      // 异步更新数据
      // setTimeout 仅做示例,真实场景中一般为 ajax 请求
      setTimeout(() => {
     
        for (let i = 0; i < 10; i++) {
     
          this.list.push(this.list.length + 1)
        }

        // 加载状态结束
        this.loading = false

        // 数据全部加载完成
        if (this.list.length >= 40) {
     
          this.finished = true
        }
      }, 1000)
    }
  }
}
</script>

<style scoped lang="less"></style>

4、搜索组件内容如下:

<template>
  <div class="search-container">
    <!-- 搜索栏 -->
    <!--
      Tips: 在 van-search 外层增加 form 标签,且 action 不为空,即可在 iOS 输入法中显示搜索按钮
     -->
    <form action="/">
      <van-search
        v-model="searchText"
        show-action
        placeholder="请输入搜索关键词"
        background="#3296fa"
        @search="onSearch"
        @cancel="onCancel"
      />
    </form>
    <!-- /搜索栏 -->

    <!-- 搜索历史记录 -->
    <search-history />
    <!-- /搜索历史记录 -->

    <!-- 联想建议 -->
    <search-suggestion />
    <!-- /联想建议 -->

    <!-- 历史记录 -->
    <search-result />
    <!-- /历史记录 -->
  </div>
</template>

<script>
import SearchHistory from './components/search-history'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 移动端项目源码通常包括以下几个方面的内容: 1. **Vue 项目结构**:Vue 项目通常采用一定的结构,包括src目录下的assets、components、router、views、utils等文件夹。其中assets存放静态资源,components存放业务组件,router存放路由配置,views存放页面组件,utils存放工具类等。 2. **移动端适配**:移动端项目通常需要针对不同屏幕尺寸进行适配,可以使用rem、vw/vh单位,或采用第三方库如flexible.js、postcss-pxtorem等进行适配。 3. **移动端交互**:移动端项目通常会涉及到一些与用户交互相关的功能,比如手势操作、滑动、拖拽等,这些交互需要通过合适的组件或库来实现,比如使用vue-touch、better-scroll等。 4. **网络请求**:移动端项目通常需要与后端进行数据交互,可以使用axios、fetch等库进行网络请求,同时需要处理接口的异常情况、数据的格式化等。 5. **优化与打包**:移动端项目需要考虑性能优化,比如减少http请求、减小资源体积、使用懒加载、代码分割等。另外,还需要对项目进行打包,生成适合移动端环境的代码包。 6. **页面跳转与状态管理**:移动端项目中页面之间的跳转通常通过路由进行管理,同时还需要对页面状态进行管理,可以使用vuex等状态管理工具来实现。 综上所述,Vue 移动端项目源码包括了项目的结构、移动端适配、交互、网络请求、优化与打包、页面跳转与状态管理等方面的内容。同时,针对具体的项目需求,源码中可能还会涉及到其他方面的内容,比如权限控制、国际化等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值