基于实战开发垂直搜索引擎_基于Vue3.0开发知乎日报实战

基于Vue3.0开发知乎日报实战

11cbe641fed19ba9d0aba8f5238a9a19.png
vue

项目界面

一个简单的小项目,基于Vue3.0 + axios + swiper实现。让大家对Vue3.0 API有一些新的认识。

9168ac02df9e74a31c76b1bc184ee297.gif
zhihu

前言

Vue3.0个人觉得学习挺容易的,Vue2.0水平怎么样,Vue3.0也就差不多那样,所以Vue2.0学的不太好的同学还是回去补一补,现阶段急于学习Vue3.0反而容易造成知识混淆。很多写法和Vue2.0相似,学习成本不高,但是很多底层东西进行的重构,所以目前不建议直接使用在公司项目上。

个人建议

目前Vue3.0开发版接近尾声,预计下个月就上线稳定版,存在以下问题,不建议在公司项目直接使用,估计还的等一段时间吧。

  • "vue-router": "^4.0.0-alpha.6" 还在开发中。这个阶段还未定型,今天解决的BUG可能明天就是另外的Bug。
  • 第三方库还未兼容到Vue3.0意想不到的兼容性等问题。
  • Vue3.0 API部分功能还未完善,Vue2.0和Vue3.0去实现。
  • 遇到技术难点,需要花大把时间去琢磨。一些问题涉及基础的东西,底子不牢,也能难查出问题所在。

综上所述,用在公司项目上,估计得折腾得够呛,或者未能按时间开发完成,产品问题多还会被扣奖金绩效等,吃力不讨好。

但是做为先行者去学习和开发项目,收益颇丰,更加能体会Vue开发者如何去架构和设计思想所在。

项目实战

Vue 3.0 在兼容 2.x 基础上做改进。且能使用Vue 3.0 新特性。

初始化项目

1、安装 vue-cli3

npm install -g @vue/cli

2、创建项目

vue create zhihuVue CLI v4.4.6? Please pick a preset:  default (babel, eslint)> Manually select featuresbabel:javascript转译器,将最新版的js语法(es6、es7)转换为现阶段浏览器可以兼容的js代码typescript:使用 TypeScript 书写源码PWA:渐进式WEB应用Router:使用vue-routerVuex:使用vuexCSS Pre-processors:css预处理器Linter / Formatter:代码规范标准Unit Testing:单元测试E2E Testing:e2e测试? Please pick a preset: Manually select features? Check the features needed for your project: (*) Babel ( ) TypeScript ( ) Progressive Web App (PWA) Support (*) Router ( ) Vuex>(*) CSS Pre-processors ( ) Linter / Formatter ( ) Unit Testing ( ) E2E Testing

3、Vue版本升级

vue add vue-next// 将Vue 2.6.x版本升级到

查看项目package.json

  "dependencies": {     "vue": "^3.0.0-beta.1",     "vue-router": "^4.0.0-alpha.6"    },    "devDependencies": {    "@vue/cli-plugin-babel": "~4.4.0",    "@vue/cli-plugin-eslint": "~4.4.0",    "@vue/cli-plugin-router": "~4.4.0",    "@vue/cli-service": "~4.4.0",    "@vue/compiler-sfc": "^3.0.0-beta.1",    "@vue/eslint-config-prettier": "^6.0.0",    "babel-eslint": "^10.1.0",    "eslint": "^6.7.2",    "eslint-plugin-prettier": "^3.1.3",    "eslint-plugin-vue": "^7.0.0-alpha.0",    "less": "^3.0.4",    "less-loader": "^5.0.0",    "prettier": "^1.19.1",    "vue-cli-plugin-vue-next": "~0.1.3"  },

vue-router 还在开发中,vue-cli-plugin-vue-next 用来处理Vue3.0编译相关语法。

静态页面

项目布局,静态页面,略过

项目结构

.├── src│   ├── api│   ├── assets│   ├── components│   ├── router│   ├── utils│   ├── views│   ├── App.vue│   └── main.js├── public├── vue.config.js└── package.json
  • src/api: 用于存放接口和管理。
  • src/assets: 静态资源目录。
  • src/components: 用于存放全局组件。
  • src/router: 用于存放路由相关的文件。
  • src/utils: 用于存放工具类相关的文件
  • src/views: 用于存放视图相关组件。

项目 Vue3.0 API 知识点

setup

setup 函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点。

生命周期

创建组件实例,然后初始化 props ,紧接着就调用setup 函数。从生命周期钩子的视角来看,它会在 beforeCreate 钩子之前被调用。

注意事项:

this 不能使用,了解Vue2.0的同学应该知道,在这生命周期之间。data()数据还未生成,所以 this.xx不能调用的。

响应式数据

Vue2.0 存放在data() {return {} } 就可以直接调用,而Vue3.0则需要通过ref或者reactive 来声明响应式数据。

ref

接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value。

const count = ref(0)console.log(count.value) // 0count.value++console.log(count.value) // 1

如果传入 ref 的是一个对象,将调用 reactive 方法进行深层响应转换。

reactive

接收一个普通对象然后返回该普通对象的响应式代理。

const obj = reactive({ count: 0 })

计算属性 computed

computed 传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象。

const count = ref(1)const plusOne = computed(() => count.value + 1)console.log(plusOne.value) // 2

watch

watch 需要侦听特定的数据源,并在回调函数中执行副作用。

const count = ref(0)watch(count, (count, prevCount) => {  /* ... */})

以上教程皆来自 Vue 组合式 API

实战

项目如果太抠细节的去讲,不知道从何说起,以下主要分为几个功能阐述这个项目。想了解项目更多细节,可以克隆我的项目,运行调试。

时间处理

src/utils/index.js

function formatTime(time) {  let arr = [];  time = time.toLocaleDateString();  time.replace(/\d+/g, (val) => {    val = val < 2 ? `0${val}` : val;    arr.push(val);  });  return arr;}function convertTime(time) {  time = time.replace(/^(\d{4})(\d{2})(\d{2})$/g,(_,g1,g2,g3)=>{    return `${g1}/${g2}/${g3}`  })  return new Date(time);}export default {  formatTime,  convertTime,};

formatTime()中的参数timenew Date()的标准日期格式,然后通过toLocaleDateString()转成2020/7/21,在依次添加到数组里面。

在不同环境下,输出不同结果。`toLocaleDateString` // 浏览器["2020", "7", "21"]// [Running] node[ '7', '21', '2020']

convertTime方法:将格式20200721转成2020/07/21的正则表达式。

应用

import utils from "../utils";const state = reactive({  date: new Date(),  bannerData: [],  newsData: []});let day = computed(() => utils.formatTime(state.date)[2]);let month = computed(() => utils.formatTime(state.date)[1]);    return { day, month};

通过计算属性,计算出几月份和几日。写法不像Vue2.0直接包裹在computed里面。

请求接口

src/api/目录下的axios.jsaxios进行二次封装,zhihu.js相关的知乎日报接口。index.js对多个接口进行整合。

// zhihu.jsimport axios from './axios'function API_LATEST(){  return axios.get('/news/latest')}function API_DETAIL(id){  return axios.get(`/news/${id}`)}export default {  API_LATEST,  API_DETAIL}// index.jsimport zhihu from './zhihu'export default { zhihu }

应用

import API from "../api";export default {  setup() {    const state = reactive({      bannerData: [],      newsData: []    });     // 在渲染组件前,异步加载数据    onBeforeMount(async () => {      const { date, stories, top_stories } = await API.zhihu.API_LATEST();      state.date = utils.convertTime(date);      state.newsData.push({        date: state.date,        stories      });      state.bannerData = top_stories;    });    return {      ...toRefs(state)    };  }

初始化轮播图

import { watch } from "vue";function initSwiper() {  new Swiper(".swiper-container", {    loop: true,    pagination: {      el: ".swiper-pagination"    }  });}setup(props) { watch(   () => props.bannerData,   () => initSwiper() );}

注意点:当获取轮播图的数据赋值到state上,此时数据还未渲染到组件上。

解决方法:

  • Vue2.0调用Vue.nextTick API(在下次 DOM 更新循环结束之后执行延迟回调。)去执行初始化。
  • Vue3.0 通过watch 去监听数据改变,在执行初始化。

详情页的功能

点击列表详情页时候,需要携带一个文章的ID过去,去请求详情接口获取更多内容。如果我上面说的setup()方法有印象的话,在setup()中不能调用this。习惯了Vue2.0跳转方式this.$router.push({name: 'detail',params:{id: xx}})Vue3.0突然不知如何下手,好在Vue2.0还提供组件式跳转。

获取路由的参数

Vue3.0路由还在开发中,暂时还未能获取路由的参数API,只能先用Vue2.0写法先代替了。

难点:如何在Vue2.0中修改Vue3.0的值,且还能被watch监听到。

解决方法:

直接用Vue2.0中实现功能。(嗯,我这是Vue3.0教程当然得用Vue3.0去实现咯)

我在Vue3.0中,我先声明了响应式数据,通过Vue2.0获取路由参数后,尝试this.id = xx  打印下log,输出this对象如下,功能实现了。

8577294e08699e4c098738ba6c42cd80.png
-w388

然而reactive的方式去声明响应式数据,其他不变,发现并能查到id。深入之后了解到ref和Vue2.0的data( return {} )底层原理都是基于Object.definedproperty实现,所以可以通过this去修改。reactive则式Prxoy实现的。还有ref中包裹是个对象话,也会通过Prxoy实现。

import { watch, toRefs,ref,reactive } from "vue";import API from "../api";export default {  setup() {    let id = ref(0);    let state = reactive({      image: '',      body: '',      title: '',      section: ''    });    watch(id, async () => {      let { image, body, title,section } = await API.zhihu.API_DETAIL(id.value)      state.image = image      state.body = body      state.title = title,      state.section = section? section.name : '佚名'    });    return {      id,      ...toRefs(state)    }  },  beforeMount(){    let { id } = this.$route.params    this.id = id  }};

完整的项目

知乎日报https://github.com/qqlcx5/zhihu

总结

Vue3.0实现知乎日报个人感觉还是不错,新写法或多或少有些不习惯,比如有个toRef少写s,调试了半天也没报错,好在后面注意到了。多写几次后就会习惯,对比Vue3.0的各方面提升,一些写法的变化,无可厚非。所以还是尽快去熟悉Vue3.0的知识,等UI库等兼容Vue3.0版本上线就正式使用了。相信这一天很快来临。

订阅

4aa722a46533690897b32b30cf11611a.png
WeChat

参考链接:

珠峰架构课


版权声明:本文为weixin_39603492原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。