一、vue3项目
创建vue3项目 : 基于构建工具webpack
vue create 项目名称
- 基于webpack的项目有一个问题,就是编译慢
- 解决:使用vite
- vite优势:在开发过程中大大提升我们的效率
二、 创建vue3项目 : 基于vite
npm init vite 项目名称
**如果选择vue的项目,默认版本是vue3
vite + vue3 的方式:
- 把create创建vue的src整个复制粘贴到基于vite的项目中
- 把create创建的package.json中的
"dependencies": {
"core-js": "^3.6.5",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0",
"vuex": "^4.0.0-0"
},
**复制粘贴到vite的项目中
-
npm i :安装依赖
-
npm run dev 启动修改错误
vite + vue2 的方式:
- 把create创建vue的src整个复制粘贴到基于vite的项目中
- 把create创建的package.json中的
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vuex": "^3.4.0"
},
**复制粘贴到vite的项目中
-
npm i :安装依赖
-
注意会报错,在安装npm install vite-plugin-vue2 -D
-
在vite.config.js配置
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
export default {
plugins: [
createVuePlugin(/* options */)
],
}
- cnpm i vue-template-compiler -S
三、vue-cli : vue3
//vue2写法
<script>
import HelloWorld from "../components/HelloWorld.vue";
export default {
name: "Home",
data () {
return {
}
},
components: {
HelloWorld,
},
};
</script>
//vue3写法
<script setup>
</script>
四、vue-cli : vue3
1.1、v-if 与 v-for 的优先级对比
2.x 版本中 v-for > v-if
3.x 版本中 v-if > v-for
1.2、v-for 中的 Ref 数组
- vue2.x 会自动把ref填充内容
- vue3.x 需要手动添加
<ul>
<li v-for="item in 5" :key="item" :ref="setItemRef">{{ item }}</li>
</ul>
methods: {
setItemRef(el){
this.arr.push(el);
}
}
1.3 $children
- vue2.x : 访问当前实例的子组件
- vue3.x : 在 3.x 中,$children 已被移除,且不再支持。
设置:<HelloWorld msg="Welcome" ref='hw'/>
访问:this.$refs.hw
五、setup
是什么 : 组合式 API
来解决什么问题 : 使用 (data、computed、methods、watch) 组件选项来组织逻辑通常都很有效。然而,当我们的组件开始变得更大时,逻辑关注点的列表也会增长。尤其对于那些一开始没有编写这些组件的人来说,这会导致组件难以阅读和理解。
响应区别:
- vue2.x : Object.defineProperty()
- vue3.x : Proxy
Object.defineProperty()存在的问题
- 不能监听数组的变化
- 必须遍历对象的每一个属性
Proxy 不需要遍历
使用渲染函数:
- ref : 就是定义数据的 简单类型
- reactive : 就是定义数据的 复杂类型
setup语法糖插件 : unplugin-auto-import
解决场景 : 在组件中开发无需每次都引入 import { ref,reactive } from 'vue'
1、下载安装
npm i unplugin-auto-import -D
2、配置:vite.config.js中
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
AutoImport({
imports: ['vue', 'vue-router']//自动导入vue和vue-router相关函数
})
],
})
toRefs:
toRefs 函数 来完成数据的解构
computed:
-
let obj = reactive({ name: '张三', age: 18, str: computed(() => { return obj.name.slice(1, 2) }) })
-
let msgChange = computed(() => { return msg.value.slice(1, 3); })
-
let msgChange = computed({ get() { return msg.value.slice(1, 3); }, set() { console.log('设置了') } })
watch:
vue2.x :
watch: {
obj: {
handler(newVal, oldVal){
console.log(newVal, oldVal)
},
immediate: true,
deep: true
}
}
vue3.x :
- 监听数据数据「初始化监听」
watch(msg, (newVal, oldVal) => { console.log(newVal, oldVal) }, { immediate: true })
- 监听多个数据「一起监听」
watch([msg, str], (newVal, oldVal) => { console.log(newVal, oldVal) }, { immediate: true })
- 监听“对象”中某个对象
watch(() => obj.arr, (newVal, oldVal) => { console.log(newVal, oldVal) })
- 立即执行监听函数
watchEffect(() => { console.log(msg.value) })
参考链接:https://v3.cn.vuejs.org/api/computed-watch-api.html#watcheffect
六、生命周期
选项式 API
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- ....
setup 组合式API
注意:没有beforeCreate和created
其他生命周期要使用前面加"on" 例如:onMounted
参考链接:https://v3.cn.vuejs.org/guide/composition-api-lifecycle-hooks.html
七、路由
- useRoute ==> this.$route
- useRouter ==> this.$router
八、组件之间的通信(特别重要)
父传子:
父:
<template>
<div>
<List :msg="msg"></List>
</div>
</template>
<script setup>
import List from '../components/List.vue'
let msg = ref('这是父传过去的数据');
</script>
子:
<template>
<div>这是子组件 ==> {{ msg }}</div>
</template>
<script setup>
defineProps({
msg: {
type: String,
default: '1111'
}
})
</script>
子传父:
一、第一种给方式:
子:
<template>
<div>
这是子组件 ==> {{ num }}
<button @click="changeNum">按钮</button>
</div>
</template>
<script setup lang='ts'>
let num = ref(200);
const emit = defineEmits<{
(e: "fn", id: number): void;
}>();
const changeNum = () => {
emit("fn", num);
};
</script>
父:
<template>
<div>
<List @fn="changeHome"></List>
</div>
</template>
<script setup>
import List from '../components/List.vue'
const changeHome = (n) => {
console.log(n.value);
}
</script>
二、第二种给方式:
子:
<template>
<div>
<button @click="mesBtn">按钮</button>
</div>
</template>
<script setup>
const num = ref(10000)
const emit = defineEmits(['fn'])
const mesBtn = () => {
emit('fn', num)
}
</script>
父:
<template>
<div>
<Hellow @fn="changeList"></Hellow>
<h3>{{str}}</h3>
</div>
</template>
<script setup>
import Hellow from '../components/Hellow.vue'
const str = ref();
const changeList = (n) => {
str.value = n.value;
}
</script>
v-model传值(双向的,可以修改)
父:
<template>
<div>
<h1>
<Hellow v-model:List="List"></Hellow>
</h1>
</div>
</template>
<script setup>
import Hellow from '../components/Hellow.vue';
const List = ref('永远爱你是我说过')
</script>
子:
<template>
<div>
子:{{List}}
<button @click="btn">按钮</button>
</div>
</template>
<script setup>
const props = defineProps({
List: {
type: String,
default: '安安'
}
})
const emit = defineEmits(['update:List'])
const btn = () => {
emit('update:List', '啊和你说过');
}
</script>
兄弟组件之间的传值:
一、下载安装
- npm install mitt -S
二、plugins/Bus.js
- mport mitt from 'mitt';
- const emitter = mitt();
- export default emitter;
三、A组件
- emitter.emit('fn',str);
四、B组件
emitter.on('fn', e => {
s.value = e.value;
})
八、插槽
匿名插槽
父:
<A>
这是xxxxx数据
这是yyyyy数据
</A>
子:
<header>
<div>头部</div>
<slot></slot>
</header>
<footer>
<div>底部</div>
<slot></slot>
</footer>
具名插槽
父:
<A>
<template v-slot:xxx>这是xxxxx数据</template>
<template v-slot:yyy>这是yyyyy数据</template>
</A>
***简写:<template #xxx>
子:
<header>
<div>头部</div>
<slot name="xxx"></slot>
<slot name="yyy"></slot>
</header>
<footer>
<div>底部</div>
<slot name="xxx"></slot>
</footer>
作用域插槽
父:
<A>
<template v-slot="{data}">{{ data.name }} --> {{ data.age }}</template>
</A>
*****简写:<template #default='{data}'>
子:
<div v-for="item in list" :key="item.id">
<slot :data="item"></slot>
</div>
动态插槽:
就是通过数据进行切换
父:
<template #[xxx]>这是xxxxx数据</template>
<script setup>
let xxx = ref('xxx');
</script>
子:
<slot name="xxx"></slot>
九、Teleport : 传送
<teleport to="#container"></teleport>
<teleport to=".main"></teleport>
<teleport to="body"></teleport>
***必须传送到有这个dom的内容【顺序】
十、动态组件
<component :is="动态去切换组件"></component>
十一、异步组件
***用来提升性能
vueuse : https://vueuse.org/core/useintersectionobserver/
使用场景1
组件按需引入:当用户访问到了组件再去加载该组件
<template>
<div>
<div ref="target">
<C v-if="targetIsVisible"></C>
</div>
</div>
</template>
<script setup>
import { useIntersectionObserver } from '@vueuse/core'
const C = defineAsyncComponent(() =>
import('../components/C.vue')
)
const target = ref(null);
const targetIsVisible = ref(false);
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }]) => {
if (isIntersecting) {
targetIsVisible.value = isIntersecting
}
},
)
</script>
使用场景2
<Suspense>
<template #default>
<A></A>
</template>
<template #fallback>
加载中...
</template>
</Suspense>
<script setup>
const A = defineAsyncComponent(() =>
import('../components/A.vue')
)
</script>
打包分包处理
npm run build打包完成后,异步组件有单独的js文件,是从主体js分包出来的
A.c7d21c1a.js
C.91709cb2.js
十二、Mixin : 混入
是什么:来分发 Vue 组件中的可复用功能
setup写法
mixins/mixin.js
import { ref } from 'vue'
export default function () {
let num = ref(1);
let fav = ref(false);
let favBtn = () => {
num.value += 1;
fav.value = true;
setTimeout(() => {
fav.value = false;
}, 2000)
}
return {
num,
fav,
favBtn
}
}
组件:
<template>
<div>
这是A组件{{num}}
<button @click="favBtn">{{fav?'收藏中':'收藏'}}</button>
</div>
</template>
<script setup>
import mixin from '../mixins/mixin';
let { num, fav, favBtn } = mixin();
</script>
选项式api写法
mixins/mixin.js
export const fav = {
data() {
return {
num: 10
}
},
methods: {
favBtn(params) {
this.num += params
}
}
}
组件:
<template>
<div>
<h1>A组件</h1>
{{ num }}
<button @click='favBtn(1)'>按钮</button>
</div>
</template>
<script type="text/javascript">
import { fav } from '../mixins/mixin.js'
export default{
data () {
return {
str:'你好'
}
},
mixins:[fav]
}
</script>
十三、Provide / Inject ==> 依赖注入
提供:(父组件)
<script setup>
const num =ref(111);
provide('changeNum', num );
</script>
注入:(子组件==》包括孙子辈分的)
<template>
<div>
<h1>B组件</h1>
{{ bNum }}
</div>
</template>
<script setup>
const bNum = inject('changeNum');
</script>
十三、Vuex
import { useStore } from 'vuex';
const store = useStore();
state:
let num = computed( ()=> store.state.num );
getters:
let total = computed( ()=> store.getters.total );
mutations:
store.commit('xxx')
actions:
store.dispatch( 'xxx' )
modules:
和之前的版本使用一样
Vuex持久化存储【插件】
- npm i vuex-persistedstate -S
- import persistedState from 'vuex-persistedstate'
-
export default createStore({ modules: { user }, plugins: [ persistedState({ key: 'xiaoluxian', paths: ['user'] }) ] })