前言
通过该分享,你将快速了解到以下知识点:
- thd3.0技术涵盖范围
- quasar-cli 全局配置简介
- Quasar 与 Element-ui 的横向对比
- 文档对比
- 组件对比
- 实际代码对比
- vue3
- vue3 解决了开发时的哪些痛点
- vue3常见语法(响应式、setup语法,父子传值、事件监听、v-model语法等)
- vue3 相较于 vue2 的不同点
- pinia 解决了哪些问题
一、技术涵盖范围
知识必备
效率提升
打包构建
三方插件
二、quasar-cli 全局配置简介
-
layout等相关全局配置: scr目录下 config.ts
-
全局样式配置:src目录下app.scss配置全局样式;quasar.variables.scss配置quasar的全局样式;根目录下的tailwind.config.js 文件可全局配置 tailwind 主题样式
-
打包、代理、插件、样式引入配置:quasar.config.js
-
三方插件引入: src目录下 boot 文件夹
-
相关类型声明文件: src目录下 *.d.ts 如: env.d.ts、quasar.d.ts
-
环境变量配置: 根目录下 .env文件
-
埋点监控配置: 根目录下 index.html
三、Quasar 与 Element-ui 的横向对比
为了让大家可以更快的上手quasar这套ui框架,以及明白我们为什么选用quasar.下面会将大家熟悉的element-ui 和 quasar做横向对比。
四、vue3
vue3 解决了开发时的哪些痛点
1. 性能比Vue2快1.2~2倍: diff算法优化; 静态提升;事件侦听器缓存; ssr渲染
2. Vue3 按需编译,体积比Vue2更小: 重写了虚拟dom; 组合 API ; fragment(代码片段)
3. 支持组合API,类似React Hooks:
更好的逻辑复用;更灵活的代码组织;高内聚,低耦合
4. 更好的支持TS:
新增了 defineComponent 函数,使组件在 ts 下,更好的利用参数类型推断。如:reactive 和 ref 很具有代表性。
5. 提供了更先进的组件: Fragment;Teleport
6. proxy 相对 Object.defineProperty: proxy 可以直接监听对象,数组; 不需要初始化的时候遍历所有属性; 有 13 种拦截方法
更多...
vue3常见语法
1.组合式 API:setup()
基本用法
<script>
import { ref } from 'vue'
import PeoplePicker from './components/PeoplePicker.vue';
export default {
props: { title: String },
components: {
PeoplePicker
},
setup(props, context) {
const count = ref(0) // 返回值会暴露给模板和其他的选项式 API 钩子
// 获取props传来的值
console.log(props.title)
// 透传 Attributes(非响应式的对象,等价于 $attrs)
console.log(context.attrs)
// 插槽(非响应式的对象,等价于 $slots)
console.log(context.slots)
// 触发事件(函数,等价于 $emit)
console.log(context.emit)
// 暴露公共属性(函数)
console.log(context.expose)
return { count }
}
},
</script>
使用setup语法糖后
- 不用写setup函数;
- 组件只需要引入不需要注册;
- 属性和方法也不需要再返回,可以直接在template模板中使用
setup语法糖中新增的api
-
- defineProps:子组件接收父组件中传来的props
-
- defineEmits:子组件调用父组件中的方法
-
- defineExpose:子组件暴露属性,可以在父组件中拿到
<script setup>
import { ref } from 'vue'
import PeoplePicker from './components/PeoplePicker.vue';
export default {
const props = defineProps({ title: String })
const emit = defineEmits(['change', 'delete'])
const count = ref(0) // 返回值会暴露给模板和其他的选项式 API 钩子
// 获取props传来的值
console.log(props.title)
},
</script>
2. 响应式
举例 ref
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">
{{ count }} <!-- 无需 .value -->
</button>
</template>
举例 reactive
<script setup>
import { reactive } from 'vue'
const state = reactive({ count: 0 })
function increment() {
state.count++
}
</script>
<template>
<button @click="increment">
{{ state.count }}
</button>
</template>
3. 类与样式绑定
我们可以给 :class (v-bind:class 的缩写) 传递一个对象来动态切换 class:
<div :class="classObject"></div>
const classObject = reactive({
active: true,
'text-danger': false
})
4. 事件监听
watch监听对象属性变化
import { watch, reactive } from 'vue';
const obj = reactive({ count: 0 })
watch(()=>obj.count, (newValue, oldValue) => {
console.log('newValue', newValue)
console.log('oldValue', oldValue)
})
obj.count++
watch() 是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调,watchEffect就可以满足该需求。
import { watch, reactive } from 'vue';
const obj = reactive({ count: 0 })
watchEffect(() => {
console.log('value', obj.count)
})
obj.count++
5. 父子传值
子组件通过 Props 接受父组件传来的值
parent.vue
<template>
<Child title="Components Title" :isClickable="true" />
</template>
<script setup lang="ts">
import Child from './components/Child/index.vue';
</script>
child.vue
<template>
<h2 class="text-4xl text-left leading-8">
{{ title }}
</h2>
<q-btn color="primary" label="buttom" :disabled="!isClickable"/>
</template>
<script setup lang="ts">
interface Props {
title: string
isClickable?: boolean
}
withDefaults(defineProps<Props>(), {
title: '',
isClickable: false
})
</script>
子组件通过 Emit 传值给父组件
child.vue
<template>
<q-form
@submit="onSubmit"
class="q-gutter-md"
>
<q-input
filled
v-model="name"
label="Your name *"
hint="Name and surname"
lazy-rules
:rules="[ val => val && val.length > 0 || 'Please type something']"
/>
<q-input
filled
type="number"
v-model="age"
label="Your age *"
lazy-rules
:rules="[
val => val !== null && val !== '' || 'Please type your age',
val => val > 0 && val < 100 || 'Please type a real age'
]"
/>
<div>
<q-btn label="Submit" type="submit" color="primary" :disabled="!isClickable"/>
</div>
</q-form>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const name = ref('')
const age = ref()
const emits = defineEmits(['submitData'])
function onSubmit(){
const submitData = {
name: name.value,
age: age.value
};
emits('submitData', submitData)
}
</script>
parent.vue
<template>
<Child title="child Components" :isClickable="true" @submitData="getChildSubmitData" />
</template>
<script lang="ts" setup>
import Child from './components/Child/index.vue';
function getChildSubmitData (data){
console.log(data);
}
</script>
6. 组件中 v-model 用法
parent.vue
<CustomInput v-model="searchText" />
CustomInput.vue
<template>
<input v-model="value" />
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const value = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
</script>
Provide:
要为组件后代提供数据,需要使用到 provide() 函数
Inject:
要注入上层组件提供的数据,需使用 inject() 函数:
vue3 相较于 vue2 的不同点
- this基本不使用
- setUp的使用
- vue3废除过滤器 filter,通过 methods 或 computed 的方案实现
- vue3 组件模板没有唯一顶层元素的限制
- Vue3 有 createApp(),而 Vue2 的是 new Vue()
- watchEffect用来代替生命周期里的onMounted和onUpdated
- slot具名插槽的使用
- 生命周期对比
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured
- 在 Vue3 中,全局和内部 API 都经过了重构,并考虑到了 tree-shaking 的支持。因此,全局 API现在只能作为 ES 模块构建的命名导出进行访问。
pinia 解决了哪些问题
- 解决多个组件共享状态时,单向数据流的简洁性很容易被破坏的问题
- 组件之间的复杂通信,做状态统一集中管理
- 解决多个视图依赖同一状态的问题
- store 中的状态不能直接更改,唯一途径就是显式地提交
总结:存储响应式,易通信,易管理,易追踪
- Pinia vs Vuex