记一次vue3+vite+vant+axios移动端页面实践(vant上拉加载/下拉刷新,引入axios)

最近搞了个企业微信内部应用(OA),想着内部使用就拿了vue3来练手。

vue3 出来很久了,目前版本 @3.2⇲, 另外 中文网站 也出来了,作为一个英文差的伸手党也应该学习起来了,哈哈~~~

UI框架我选择了 [email protected] ,其官网地址⇲。

趁着周末,以 Vant上拉加载/下拉刷新 为切入点,慢慢铺开 vue3 的一些小知识点。

本文使用的 IDE 是 vscode, 对于vue3语法 ,官方更推荐 volar 插件支持。
注意 vue3 要求 node 版本 > 12

这篇 ~~高质量程序员~~ 的文章,能不能让我花三个小时得到你们的18个赞。
记一次vue3+vite+vant+axios移动端页面实践(vant上拉加载/下拉刷新,引入axios)_第1张图片

目录

  • 创建一个项目
  • vue3基础知识
    • vue-router && vuex
    • 向上兼容
    • Composition API
      • setup
      • 生命周期
      • 定义数据和方法
      • 全局变量和组件
      • `provide/reject`(引入axios)
        • 引入axios
      • dom元素获取之ref
      • 父子父组件的通信
      • 其它
  • 引入vant
    • 全局引入
      • 安装
      • 全局引入
      • 使用
    • 按需引入
      • vant下拉刷新、上拉加载代码
    • 基于 `provide/reject`, `sessionStorage` 搞一个自己的状态存储
    • 最后
  • 参考


创建一个项目

Vite 创建一个 Vue3项目(名为vue_next), 只需要以下命令

# yarn 推荐
yarn create vite vue_next
# npm
npm init vite vue_next

我这样安装的vue版本是 3.0.4

记一次vue3+vite+vant+axios移动端页面实践(vant上拉加载/下拉刷新,引入axios)_第2张图片
项目初始目录:

|-node_modules      -- 项目依赖包的目录
|-public            -- 项目公用文件
  |--favicon.ico    -- 网站地址栏前面的小图标
|-src               -- 源文件目录,程序员主要工作的地方
  |-assets          -- 静态文件目录,图片图标,比如网站logo
  |-components      -- Vue3.x的自定义组件目录
  |--App.vue        -- 项目的根组件,单页应用都需要的
  |--index.css      -- 一般项目的通用CSS样式写在这里,main.js引入
  |--main.js        -- 项目入口文件,SPA单页应用都需要入口文件
|--.gitignore       -- git的管理配置文件,设置那些目录或文件不管理
|-- index.html      -- 项目的默认首页,Vue的组件需要挂载到这个文件上
|-- package-lock.json --项目包的锁定文件,用于防止包版本不一样导致的错误
|-- package.json    -- 项目配置文件,包管理、项目名称、版本和命令

照着指示,进入 => 安装依赖 => 运行 即可

cd vue_next
npm install (or `yarn`)
npm run dev (or `yarn dev`)

记一次vue3+vite+vant+axios移动端页面实践(vant上拉加载/下拉刷新,引入axios)_第3张图片
浏览器打开相应地址就行了。

vite 很香,自带热更新,配置项在根目录 vite.config.js (需要新建),细则见 官网

为了后面案例的展开,先补充一点点 vue3 的知识。


vue3基础知识

vue-router && vuex

这两个没什么大的变化,不做重点讲解。使用时移步官网即可。

  • 状态管理推荐 pinia 方案,vue2/3均支持。
  • 下面也会提到 基于 provide/injectsessionStorage 的小方案

向上兼容

注意,你仍然可以像写 vue2.x 那样写vue3。除了部分不兼容外(错误时会有提示)
个人认为 vue3 最大改动就是加入了 Composition API ,所以这将是本文的实践方式。

Composition API

Composition API 翻译过来就是 组合式接口,官方推荐使用代替原来的选项式(Options Api)书写。
其实这种方式更接近 js ,不同的就是就是写在了 setup 函数里。

setup

Composition API的大概意思就是数据和逻辑全部写在 setup函数 里面,把它当做一个函数即可,接受两个参数 props(属性), context(上下文)。
context主要有三个属性 attrs, slots, emit

//xxx.vue
<template>
</template>

<script>
export default {
  setup(props, { attrs, slots, emit }) {
    console.log(props.title, )
  }
}
</script>

props

  • 接受的自定义属性, 响应式的。

context.attrs

  • 所有传入的属性,非响应式。如果要根据变化做响应操作,建议 onUpdated 中调用

context.slots

  • 插槽,非响应式。如果要根据变化做响应操作,建议 onUpdated 中调用。

context.emit

  • 向父组件中提交事件,和原来 this.$emit 相同

生命周期

有一些 更改, 更改之后,与路由守卫周期,自定义指令周期都一致了。

2.x 周期 选项式 API setup
beforeCreate beforeCreate Not needed*(setup)
created created Not needed*(setup)
beforeMount beforeMount onBeforeMount
mounted mounted onMounted
beforeUpdate beforeUpdate onBeforeUpdate
updated updated onUpdated
beforeDestroy beforeUnmount onBeforeUnmount
destroyed unmounted onUnmounted
errorCaptured errorCaptured onErrorCaptured
- renderTracked onRenderTracked
- renderTriggered onRenderTriggered
- activated onActivated
- deactivated onDeactivated

定义数据和方法

数据可以有响应性和非响应性,但最后都得返回以暴露给 template 中使用

  • 非响应式数据
//xxx.vue
<template>
  <span>{{ name }}</span>
</template>

<script>
export default {
  name: 'App',
  setup(props) {
   const name = "非响应常量";
   return { name } // 暴露出去
  }
}
</script>
  • 响应式数据

对于响应式数据 vue 提供了两个API refreactive .个人认为基础数据类型用 ref, 否者用reactive 。写多了之后其实我都放在了 reactive 里面,因为优雅)。

<template>
  <span>{{ name }}</span>
  <p v-for="item in state.arr" :key="item.id">{{item}}</p>
</template>

<script>
import { ref, reactive } from 'vue';
export default {
  name: 'App',
  setup(){
    let name = ref('响应式变量');
    // 在 setup内部使用 ref 包裹的变量要用 .value
    name.value = 'new name';
    const state = reactive({ arr: [{id: 1, name: '响应项'}] })
    return { name,  state }
  }
}
</script>
  • 语法糖 unref, toRefs

unref 主要是获取 非响应 和 响应 的值

import { unref } from 'vue';
// 相当于 val = isRef(name) ? name.value : name
const val= unref(name)

toRefs 是将响应式对象转换为普通对象。可以转化上面提到的 props,说是语法糖有点牵强,不过我常常把它当做语法糖用。如下书写后,便可以在模版内少写 state, 很香.

<template>
  <p v-for="item in arr" :key="item.id">{{item}}</p>
</template>

<script>
import { toRefs } from 'vue';
export default {
  name: 'App',
  setup(props){
	const title = toRef(props, 'title')
	console.log(title.value)
    const state = reactive({ arr: [{id: 1, name: '响应项'}] })
    return { ...toRefs(state) }
  }
}
</script>
  • 定义方法

和上面变量一样, 先定义后暴露即可

// template
<button @click="handleSubmit"></button>
// script	setup 内部
const handleSubmit = () => {/* somde code*/ }
return { 
 // 方法
 handleSubmit
}

全局变量和组件

在vue2.x 中 axios 引入就是通过 Vue.prototype.$http 定义全局属性以便在单文件组件中使用,注意这种方式在vue3中将不起作用, 相关 地址

作为替代: Vue.prototype 替换为 config.globalProperties

const app = createApp({})
app.config.globalProperties.$http = () => {}

其实这种方式 在 setup 中使用会有问题,考虑使用 provide/reject,下面会做介绍。

先介绍一下全局组件,全局注册

const app = Vue.createApp({})
app.component('component-a', {
  /* ... */
})

稍微可以封装一下

// src/common/thirdComponent.js
import HelloWorld from '../../components/HelloWorld.vue';
export default function initGloabalComponents(app) {
	app.component(HelloWorld);
}
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import initGloabalComponents from "./common/thirdComponent"

const bootstrap = () => {
  initGloabalComponents(app);
}
bootstrap();
app.mount('#app')

provide/reject(引入axios)

上面提到 app.config.globalProperties.$http 在 setup中使用会有问题, 可使用 provide/reject

这个⇲ 很好用,不仅能解决上面的问题,还可以 二次封装 第三方组件(引入vant时会提到),做一个自己的 mini vuex(后面会提到)。

当编写不依赖 vuex 的组件库时,这或许是 vue 提供的一个让人 amazing‍♂️ 的 Api!

使用 axios 为例。

引入axios

先安装

yarn add axios -S

只需要在main.js中注入

//main.js
import axios http from "axios";
app.provide('$http', axios);
<script>
import { provide, inject } from 'vue';
export default {
  name: 'App',
  setup(){
     // 如果要在template中使用便用return 暴露出去
     const _http = inject('$http');
     const fetchUser = () => {
      _http.get(url).then(res => {})
     }
     // 可以暴露一个本组件的全局变量以便其所有子组件(一层或多层)使用
     // 子组件用 inject('varible') 接收
     provide('varible');
  }
}
</script>

如果想稍微封装一下或者想深入 axios, 推荐

  • 如何让axios在vue中丝滑起来
  • Axios源码初探

dom元素获取之ref

获取元素是我们常见的需求,vue2.x 提供了 this.$refs.xxx 获取 ref="xxx" 的元素。
在vue3中,依然是 在 元素/组件 增加属性 ref="xxx", 获取时有一些不同。

// 注意一致性!!!
<template>
  <span ref="xxx0"></span>	
  <HelloWorld msg="Hello Vue 3.0 + Vite" ref="xxx1" />
</template>
<script>
import { ref } from 'vue';
export default {
  name: 'App',
  setup(){
    const xxx0 = ref(null);
    const xxx1 = ref(null);
    // 是一个对象, $el 是相应的dom
	console.log(xxx0.value, xxx1.value)
	return { xxx0, xxx1 }
  }
}
</script>

父子父组件的通信

父子组件常常是需要触发对方的方法或者传值, 前面提 setup 时提及到一些知识,这里完善一下,建议参考 组件基础⇲。

  • 父组件传值给子组件
<template><!-- child.vue --></template>
<script>
import { toRef } from 'vue';
export default {
  name: 'App',
  setup(props){
  	console.log(props.title);
	const title = toRef(props, 'title')
	console.log(title.value)
    return { title }
  }
}
</script>
  • 父组件调用子组件方法&子组件调用父组件方法
// pareant.vue
<template>
	<child ref="childRef" @bindFunc="handleFromChild"></child>
</template>
<script>
import { ref } from 'vue';
export default {
  name: 'App',
  setup(){
  	const childRef= ref(null);
  	// 调用 child 组件的 childFunc 方法, 
  	childRef.value.childFunc(params2);
  	
  	const handleFromChild = (params1) => {}
    return { childRef, handleFromChild }
  }
}
</script>
// child.vue
<template>
	<span>child</span>
</template>
<script>
export default {
  name: 'App',
  setup(props, { emit }){
  	// 触发绑定的方法 bindFunc
  	emit('bindFunc', params1);
  	
  	const childFunc = (param2) => { // 子组件方法 }
  	return { childFunc }
  }
}
</script>

其它

一些API,子元素的方法什么的变更,限于篇幅我就不再提了。
当我们一个组件代码很多的时(后期很常见),需要做一些逻辑抽离,比如每个页面需要检测一下用户权限(当然完全可以在router 拦截里面做)。官网中也有提及

建议大家仔细阅读 迁移指南⇲即可


引入vant

全局引入

安装

yarn add [email protected] -D

全局引入

main.js

import { createApp } from 'vue'
import App from './App.vue'
import './index.css';
// 引入
import Vant from 'vant';
import 'vant/lib/index.css';

const app = createApp(App);
// 安装
app.use(Vant);
app.mount('#app');

使用

Helloword.vue 稍微改造一下

  • template
<template>
  <div class="list-wrapper">
    <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
      <van-list
        v-model:loading="loading"
        :finished="finished"
        finished-text="没有更多了"
        @load="onLoad"
        
                    

你可能感兴趣的:(vue,工作点滴,vue.js,vue3,vant,vite)