Vite 法語意為 "快速的"屡立,發(fā)音 /vit/话告,下一代前端開發(fā)與構(gòu)建的工具,等于現(xiàn)在的webpack泉粉。
第一感覺:npm run dev 的時(shí)候跑項(xiàng)目飛快
創(chuàng)建vue3項(xiàng)目
# npm 版本, 安裝vu3之前需要檢查npm版本號(hào)连霉,對(duì)號(hào)入座:
npm -v
# npm 6.x
npm init vite@latest my-vue-app --template vue
# npm 7+, 需要額外的雙橫線:
npm init vite@latest my-vue-app -- --template vue
安裝依賴
npm i
運(yùn)行項(xiàng)目
npm run dev
VSC安裝vue3配套插件Volar
相信使用 vscode 和 vue2的同學(xué)對(duì) vetur 這個(gè)插件一定不會(huì)陌生。
認(rèn)識(shí)頁面 template script style
<script setup>
</script>
<template>
</template>
<style scoped>
</style>
從上面的代碼可以看到嗡靡,<script setup></script>標(biāo)簽和<template></template>標(biāo)簽順序已經(jīng)更換了跺撼,但我還是習(xí)慣vue2順序,且<script setup></script>標(biāo)簽中必須使用setup關(guān)鍵字定義讨彼。
vue3響應(yīng)式視圖更新數(shù)據(jù) ref
不同于vue的data和methods,vue3是這樣創(chuàng)建響應(yīng)式對(duì)象的歉井,在vue3中需要用到ref才能觸發(fā)視圖的更新。
<template>
{{msg}}
<button @click="changeName">更換名字</button>
</template>
<script setup>
import {ref} from 'vue'
let msg = ref('李白')
function changeName(){
msg.value = '杜甫'
}
</script>
<template>
{{user.username}}
{{user.age}}
<button @click="changeAge">更換</button>
</template>
<script setup>
import {ref} from 'vue'
let user = ref({
username:'李白',
age: 18
})
function changeAge(){
user.value.age = 14
}
</script>
從上面2個(gè)demo來看点骑,我們vue3的數(shù)據(jù)響應(yīng)式需要如此來搞酣难,是不是發(fā)現(xiàn)似乎有些繁瑣谍夭?邏輯有些古怪?
響應(yīng)式reactive 取代ref憨募,恢復(fù)正常的寫法,相當(dāng)于vue2的data
<template>
{{user.username}}
{{user.age}}
<button @click="changeName">更換</button>
</template>
<script setup>
import {reactive} from 'vue'
const user = reactive({
username:'李白',
age: 18
})
function changeName(){
user.username = '王安石'
}
</script>
reactive解包寫法
<template>
<button @click="changeName">更換</button>
{{user.username}}
{{user2.username}}
</template>
<script setup>
import {ref,reactive} from 'vue'
const user = ref({
username:'李白',
})
const user2 = reactive(user.value)
function changeName(){
user2.username = '杜甫'
}
</script>
這里關(guān)注到 {{user2.username}}
事件對(duì)象和傳遞參數(shù)
<template>
{{user}}
<button @click="changeName('江山',$event)">更換</button>
</template>
<script setup>
import {ref} from 'vue'
let user = ref('李白')
function changeName(username,event){
user.value = username
//console.log(event);
console.log(username,event);
}
</script>
計(jì)算屬性
反序輸出字符串
<template>
{{reMsg}}
</template>
<script setup>
import {ref,computed} from 'vue'
let msg = ref('hello')
const reMsg = computed(() => {
return msg.value.split('').reverse().join('')
})
</script>
偵聽屬性
<template>
{{msg}}
{{user.name}}
</template>
<script setup>
import {ref,reactive,watch} from 'vue'
let msg = ref('hello')
let user = reactive({
name:'雷柏',
age: 20
})
watch(msg,(newValue,oldValue)=>{
console.log(newValue);
console.log(oldValue);
})
watch(
()=>user.name,
(newValue,oldValue)=>{
console.log(newValue);
console.log(oldValue);
}
)
</script>
父子組件傳值:子組件用defineProps接收父組件傳過來的值
值得注意的是紧索,vue3中引入組件不在需要注入,直接Import 引入菜谣,使用即可
子組件
<template>
{{title}} --- {{content}}
</template>
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
title: String,
content: String
})
</script>
<style scoped>
</style>
父組件
<template>
<HelloWorld :title="article.title" :content="article.content"></HelloWorld>
</template>
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import { reactive } from 'vue';
let article = reactive({
title: '滿江紅',
content: '歲歲年年花相似'
})
</script>
父子組件傳值:子組件發(fā)布自定義事件珠漂,通知父組件修改值 defineEmits
子組件發(fā)布事件
<template>
{{title}} --- {{content}}
<button @click="btn">修改</button>
</template>
<script setup>
import { defineProps,defineEmits } from 'vue';
const props = defineProps({
title: String,
content: String
})
const emit = defineEmits(['modifyContent','modifyTitle'])
function btn(){
emit('modifyContent')
emit('modifyTitle')
}
</script>
<style scoped>
</style>
父組件修改值
<template>
<HelloWorld
:title="article.title"
:content="article.content"
@modifyContent = "changeContent()"
@modifyTitle = "changeTitle()"
></HelloWorld>
</template>
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import { reactive } from 'vue';
let article = reactive({
title: '滿江紅',
content: '歲歲年年花相似'
})
function changeContent(){
article.title = '秦時(shí)明月'
}
function changeTitle(){
article.content = '巴山楚水凄涼地'
}
</script>
路由的創(chuàng)建與使用 vue3需要4.0版本的路由,store也是
安裝:
npm i vue-router
創(chuàng)建路由腳本:src目錄下>創(chuàng)建router目錄>index.js
編寫腳本:/src/router/index.js
import {
createRouter,
createWebHashHistory,
createWebHistory
} from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import Buycart from '../views/Buycart.vue'
const routes = [
{
path: '/home',
component: Home,
name: 'home'
},
{
path: '/about',
component: About,
name: 'about'
},
{
path: '/buycart',
component: Buycart,
name: 'buycart'
},
{
path: '/product',
component: () =>import('../views/Product.vue'),
name: 'product'
}
]
const router = createRouter({
history: createWebHistory(),
routes,
})
export default router
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
createApp(App).use(router).mount('#app') //use必須要在mount之前
路由使用
<template>
<div>
<router-view></router-view>
<router-link to="/home">跳轉(zhuǎn)首頁</router-link>
<button @click="router.push('/product')">跳轉(zhuǎn)至產(chǎn)品頁面</button>
<button @click="goTo">跳轉(zhuǎn)至產(chǎn)品頁面</button>
</div>
</template>
<script setup>
import { useRoute,useRouter } from 'vue-router';
let route = useRoute()
let router = useRouter()
function goTo(){
console.log(route);
router.push('/product')
}
</script>
<style scoped>
</style>
安裝vuex,需要下一代版本,官網(wǎng)默認(rèn)也是4.0x版本
npm i vuex@next --save
創(chuàng)建目錄/src/store/index.js
import { createStore } from 'vuex'
// 創(chuàng)建一個(gè)新的 store 實(shí)例
const store = createStore({
state () {
return {
count: 0
}
},
mutations: {
increment (state,payload) {
state.count += payload
}
},
getters:{
totalPrice(state) {
return state.count*99.9
}
},
actions:{
asyncAdd(store,payload){
setTimeout(()=>{
store.commit('increment',payload)
},1000)
}
}
})
export default store
main.js引入
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import store from './store/index'
createApp(App).use(router).use(store).mount('#app') //use必須要在mount之前
頁面使用
<template>
<div>
<h1>購物車</h1>
<h2>商品數(shù)量{{store.state.count}}</h2>
<h2>商品總價(jià){{store.getters.totalPrice}}</h2>
<button @click="addProd">添加商品數(shù)量+2</button>
<button @click="asyncAddProd">異步添加商品數(shù)量+10</button>
</div>
</template>
<script setup>
import { useStore } from 'vuex';
let store = useStore()
function addProd(){
store.commit('increment',2)
}
function asyncAddProd(){
store.dispatch('asyncAdd',10)
}
</script>
suspense內(nèi)置新增組件尾膊,defineAsyncComponent異步封裝組件
調(diào)用組件
<template>
<!-- suspense內(nèi)置新增組件,數(shù)據(jù)加載回來的時(shí)做些什么,數(shù)據(jù)沒回來之前做些什么 -->
<suspense>
<template #fallback>
<h1>Loading</h1>
</template>
<template #default>
<HomeCom></HomeCom>
</template>
</suspense>
</template>
<script setup>
import * as api from '../api/index'
// vue3異步請(qǐng)求
import { onMounted,defineAsyncComponent } from 'vue';
//異步請(qǐng)求組件
const HomeCom = defineAsyncComponent(()=>import('../components/HomeCom.vue'))
onMounted(async() =>{
let res = await api.getHomepage()
//console.log(res);
})
</script>
組件
<template>
<h1>首頁</h1>
<ul>
<li v-for="(item,i) in hero">
<h3>{{item.category}}</h3>
</li>
</ul>
</template>
<script setup>
import * as api from '../api/index'
import { reactive } from 'vue'
let res = await api.getHomepage()
const hero = reactive(res.hero)
</script>