-
新修改獲取全局變量的簡(jiǎn)單的寫(xiě)法,在底部,請(qǐng)進(jìn)行查看!
-
首先我們安裝vue3.0以上的腳手架全局
cnpm install @vue/cli -init -g //兼容vue2.0的也可以下
-
創(chuàng)建項(xiàng)目
vue create 項(xiàng)目名
-
此時(shí)打開(kāi)你的package.json文件,看里面的vue版本,顯示的是2.6.1版本而不是3.0版本
"dependencies": {
"@vue/composition-api": "^0.5.0",
"core-js": "^3.6.5",
"vue": "^2.6.11",//這不是我們要用的vue3.0版本
"vue-router": "^3.2.0",//這個(gè)也是,應(yīng)該是4. 幾的版本
"vuex": "^3.4.0"http://這個(gè)也是,應(yīng)該是4. 幾的版本
},
-
在命令行輸入指令
vue add vue-next
-
這是在查看版本就好了,還有打開(kāi)vue-router和vuex文件,創(chuàng)建的方式有點(diǎn)不一樣,以前是new 一個(gè) ,現(xiàn)在是創(chuàng)建一個(gè)
"dependencies": {
"core-js": "^3.6.5",
"vue": "^3.0.0-beta.1",
"vue-class-component": "^7.2.3",
"vue-property-decorator": "^8.4.2",
"vue-router": "^4.0.0-alpha.6",
"vuex": "^4.0.0-alpha.1"
},
-
要是使用了上面的指令的話,就不用這一步了(使用vue3.0要使用自帶的composition-api,在main.js中引入)
import VueCompositionApi from '@vue/composition-api'
Vue.use(VueCompositionApi)//體驗(yàn)vue3.0
-
此時(shí)命令符會(huì)提示我們要下載這個(gè)插件,進(jìn)行下載
cnpm install --save composition-api //有點(diǎn)記不清了,可以看命令符里面的提示
-
注意:由于現(xiàn)在是正式版發(fā)布了,所以上面的API->composition-api都不用下載了,直接下載好腳手架之后,使用API可以直接引入import { ref, reactive... } from 'vue'就可以了
-
在我們需要使用vue3.0的組建中在引入并使用
<template>
<div class="hello">
<p>{{msg}}</p>
<p>{{title}}--{{age}}--{{sex}}</p>
<button @click="dian()">點(diǎn)擊</button>
<p>{{num}}</p>
<!-- <img src="@/assets/my.png" alt="我的"> -->
</div>
</template>
<script>
import {reactive,toRefs,computed} from 'vue'//下面的可以換成是這一種
import {reactive,toRefs,computed} from '@vue/composition-api'//把這個(gè)api換成vue也可以
export default {
name: 'HelloWorld',
props: {
msg: String
},
setup(){
const state=reactive({
title:'hello vue 3.0',
age:20,
sex:'男',
num:computed(()=>100)//計(jì)算屬性的方法寫(xiě)法
})
//方法,要有返回值才會(huì)顯示
let dian=()=>{
state.age+=10;
console.log(state.age);
}
// return state//返回全部的數(shù)據(jù)
// return {//返回指定的數(shù)據(jù)
// title:state.title,
// age:state.age
// }
return {
...toRefs(state),//torefs響應(yīng)式的方法,視圖更新
dian//導(dǎo)出方法,否則視圖不更新
}
}
// data () {//vue2.0的初始化數(shù)據(jù)
// return{
// aa:"hello"
// }
// },
// methods:{//方法屬性
// ac(){
// let a='bb';
// this.aa=a;
// }
// }
}
</script>
<style scoped>
</style>
-
父?jìng)髯樱╬rovide這個(gè)方法傳遞后,在子組件,孫子組件中都是可以獲取到的)
- 在父組件中
<script>
// @ is an alias to /src
import {reactive,provide} from '@vue/composition-api'
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'Home',
components: {
HelloWorld
},
setup(){
const state=reactive({
tit:'我是父組件的數(shù)據(jù),傳遞給子組件'
})
provide('ac',state.tit);//通過(guò)provide傳值第一個(gè)參數(shù)為自定義名,第二個(gè)為值
return{
...state //一定要加返回值
}
}
}
</script>
- 在子組件中
{{tit}}
<script>
import {reactive,toRefs,computed,inject} from '@vue/composition-api'
export default {
name: 'HelloWorld',
setup(){
const tit=inject('ac');//接受傳遞過(guò)來(lái)的參數(shù),要return導(dǎo)出去,否則會(huì)找不到tit
const state=reactive({
title:'hello vue 3.0',
age:20,
sex:'男',
num:computed(()=>100),//計(jì)算屬性的方法寫(xiě)法
// tit:inject('tit')//也可以這樣接受參數(shù)
})
//方法,要有返回值才會(huì)顯示
let dian=()=>{
state.age+=10;
console.log(state.age);
}
return {
...toRefs(state),//torefs響應(yīng)式的方法,視圖更新
dian,
tit
}
}
}
</script>
-
路由跳轉(zhuǎn)(getCurrentInstance使用這個(gè)API也是可以的喲!)
<button @click="toPage('About')">點(diǎn)擊跳轉(zhuǎn)頁(yè)面</button>
<script>
import {ref} from 'vue'
import {useRouter} from 'vue-router'
export default {
setup(){
const name=ref('我是vue3.0嘗鮮版本');
const abc=ref('相當(dāng)于是一個(gè)導(dǎo)出');
const create=ref(`<p>我是一個(gè)p標(biāo)簽</p>`);
const router=useRouter();//路由跳轉(zhuǎn)
const toPage=path=>router.push(path);
return {
name,abc,create,toPage
}
}
}
</script>
-
監(jiān)聽(tīng)路由
import { useRouter } from 'vue-router';
<template>
<div id="app">
<div id="nav">
<h1>{{title}}</h1>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<script>
import {useRouter} from 'vue-router';
// import { ref , watch } from 'vue';
import {watchEffect , ref } from 'vue';
export default {
setup(){//這是使用的監(jiān)聽(tīng)屬性
const title=ref('我是home主頁(yè)面');
const route=useRouter();
* 這是監(jiān)聽(tīng)路由的第一種寫(xiě)法
// watch(route.currentRoute,({path})=>{//{path}==》相當(dāng)于是解構(gòu)賦值
// console.log(route.currentRoute.value);
// console.log(path);
// const ad = path==='/'?'我是home主頁(yè)面':'我是about頁(yè)面';
// title.value = ad ;
// if(path==='/'){
// title.value='我是home主頁(yè)面';
// }else{
// title.value='我是about頁(yè)面';
// }
// })
* 這是監(jiān)聽(tīng)路由的第二種寫(xiě)法(推薦)
watchEffect(()=>{//比監(jiān)聽(tīng)watch好用一些,剛開(kāi)始進(jìn)入頁(yè)面就會(huì)監(jiān)聽(tīng)
console.log(route.currentRoute.value);
const {path}=route.currentRoute.value;
const ad = path==='/'?'我是home主頁(yè)面':'我是about頁(yè)面';
title.value = ad ;
})
return{
title
}
}
}
</script>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>
-
計(jì)算屬性(監(jiān)聽(tīng)路由的變化)
import { useRouter } from 'vue-router';
<template>
<div id="app">
<div id="nav">
<h1>{{title}}</h1>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<script>
import {useRouter} from 'vue-router';
import {computed} from 'vue';
export default {
setup(){//使用計(jì)算屬性進(jìn)行渲染
const route=useRouter();
const title=computed(()=>{
const {path}=route.currentRoute.value;
return path==='/'?'我是home主頁(yè)面':'我是about頁(yè)面';
})
return{
title
}
}
}
</script>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>
-
點(diǎn)擊事件
quit()加括號(hào),方法有參數(shù)才會(huì)執(zhí)行,要是不加括號(hào),方法有參數(shù),會(huì)不執(zhí)行,打印顯示默認(rèn)參數(shù)$event參數(shù)
<button @click="quit()">返回home頁(yè)</button>
import {useRouter} from 'vue-router';
export default {
setup(){
const route=useRouter();
const quit=(lev=-1)=>route.go(lev);//lev默認(rèn)值為-1,傳值就是當(dāng)前的值
return{
quit
}
}
}
-
傳值(相當(dāng)于是vuex)
- 先新建一個(gè)chaunZhi.js文件
//相當(dāng)于vuex傳值一樣
import {ref} from 'vue';
const num1=ref(1000);//這是渲染頁(yè)面的數(shù)字
const dianJi=(num=1)=>{//這是方法
num1.value+=num;
}
export {//導(dǎo)出
num1,dianJi
}
- 在about.vue頁(yè)面引入
<p>你被點(diǎn)擊了多{{num1}}次</p>
<button @click="dianJi()">點(diǎn)擊</button>
<script>
import {num1,dianJi} from '@/components/chaunZhi.js';
export default {
setup(){
return{
num1,dianJi
}
}
</script>
- 在app.vue頁(yè)面中再次引入
<p>你被點(diǎn)擊了{(lán){num1}}次</p>
<script>
import {num1} from '@/components/chaunZhi.js';
export default {
setup(){
return{
num1
}
}
</script>
- 此時(shí)當(dāng)在about.vue中點(diǎn)擊時(shí),在app.vue中會(huì)同步顯示
-
使用vuex
- 在vuex頁(yè)面跟我們vue2.0的寫(xiě)法是一樣的
- 在頁(yè)面中使用vuex數(shù)據(jù)(getCurrentInstance也可以使用這個(gè)API,下面有介紹,這個(gè)是可以正常輸出的)
import {useStore} from 'vuex';
export default {
setup(){
const store=useStore();
const pro=computed(()=>store.state.pro);//這是獲取state中的值
const dd=store.commit('dd');//這是調(diào)用方法
let ff=()=>{//這是2020-8-21自己再次練習(xí)的時(shí)候?qū)懙? store.commit("add")
}
return{
pro,dd
}
}
}
-
父?jìng)髯樱觽鞲?/h6>
- 跟我們?cè)赩ue2.0中的寫(xiě)法是一樣的,就是稍微的改變一些
- 父組件
list不是動(dòng)態(tài)的傳遞,所以不需要綁定,注意方法后面不加括號(hào)!!!不加括號(hào),否則數(shù)據(jù)顯示undefined
<History list="我是HOME組件進(jìn)行傳遞的數(shù)據(jù)" @ac="ac"></History>
setup(){//相當(dāng)于created或者是beforecreate
let ac=(k)=>{
console.log(k);這個(gè)參數(shù)就是我們的子組件傳遞給父組件的數(shù)據(jù)
}
},
return{
ac//--->一定要將方法return出去,否則會(huì)報(bào)錯(cuò)的喲!
}
- 子組件
<mark>{{list}}</mark>
{{b}}
export default {
props:['list'],這是接受父組件傳遞過(guò)來(lái)的參數(shù),跟Vue2.0一樣,在頁(yè)面上直接寫(xiě)就可以了
setup(props,ctx){
/**
* 父?jìng)髯樱瑢⑦@個(gè)下標(biāo)傳遞給子組件中
*/
let st=reactive({
num:0
})
let chu=()=>{
st.num++;
// console.log(st);
// console.log(props);
ctx.emit('ac',st.num);這是點(diǎn)擊后,將數(shù)據(jù)傳遞給父組件
console.log(props.list);這是獲取到父組件傳遞過(guò)來(lái)的值
}
修改父組件傳遞過(guò)來(lái)的數(shù)據(jù)
let a=reactive({
b:props.list
});
a.b='66666'將“我是HOME組件進(jìn)行傳遞的數(shù)據(jù)”改為66666
provide("chuan",st.num);//不能放到點(diǎn)擊事件中,而且值不是動(dòng)態(tài)的,只傳遞第一次的初始值
return{
chu,
st,
props,這個(gè)寫(xiě)不寫(xiě)都行,但是setup(props)這個(gè)要寫(xiě)要不ctx.emit會(huì)報(bào)錯(cuò)
...toRefs(a)
}
}
}
-
函數(shù)式的方式(為滿足業(yè)務(wù)的需求,我們需要寫(xiě)好幾百行代碼及方法,不能都寫(xiě)在setup中,這樣的話后期的維護(hù)不好維護(hù),每次都要去找,所以我們可以在函數(shù)中寫(xiě)上我們的方法等,最后在setup中return就可以了)
<p style="color:red;">{{asd.aa.value}}----111</p>這里的asd是setup中return的那個(gè)變量
<p style="color:red;">{{asd.ba.value}}----2222</p>
<p style="color:red;">{{asd.ads.value.bas}}----ref</p>ads是asd函數(shù)中的ref的值可以直接輸出asd可以看看返回的數(shù)據(jù)格式就明白了
<button @click="asd.bass()">點(diǎn)擊修改函數(shù)中的變量值{{asd.bass}}</button>方法的后面有沒(méi)有括號(hào)都可以
<script>
import { reactive, toRefs , ref } from 'vue'
function add() {
let asd=reactive({
aa:'我是一個(gè)函數(shù)',
ba:"我可以寫(xiě)多個(gè)函數(shù),在導(dǎo)出就可以了"
});
let ads=ref({
bas:'我是ref的寫(xiě)法在函數(shù)中'
})
let bass=()=>{//這是方法,相當(dāng)于Vue2.0中的methods
asd.aa="我是點(diǎn)擊事件,修改aa為666"
}
return{
...toRefs(asd),ads,bass
}
}
export default {
setup(){
return{
asd:add(),這里只需要到處一次就可以了,不需要兩次
// ads:add()
}
}
}
</script>
-
上面使用函數(shù)的寫(xiě)法有點(diǎn)子low啊,其實(shí)可以使用解構(gòu)賦值的
function add(){
let a=reactive({
b:'我是函數(shù)中的變量',
c:'可以使用解構(gòu)賦值哦'
})
return a;
}
export default {
setup(){
直接進(jìn)行解構(gòu)賦值就可以了
let {b,c}=add();
return{
c,b
}
}
}
-
teleport瞬移組件的使用(以下開(kāi)始是使用ts+vue3.0進(jìn)行的練習(xí))
- 說(shuō)明:就是之前我們使用全局注冊(cè)組件還是局部進(jìn)行注冊(cè)組件,都是在根組件app下,但是使用了teleport之后,我們可以在新建一個(gè)根組件了,相當(dāng)于有兩個(gè)及多個(gè)根組件,用法都是一樣的沒(méi)有什么改變
-
1、先新建一個(gè)組件,之后再app.vue中進(jìn)行局部注冊(cè),然后進(jìn)行使用,不過(guò)我們要在當(dāng)前的組件當(dāng)中添加上這個(gè)teleport標(biāo)簽
image.png - 然后在我們寫(xiě)的組件當(dāng)中
<template>
#Model就是我們添加到根組件的id名
<teleport to="#Model">
<mark>1322</mark>
</teleport>
</template>
- 還有最后一步喲,找到我們?cè)趐ublic下的index.html文件
image.png
- 這樣的話,再去瀏覽器中看看吧,我們的根組件就會(huì)變成兩個(gè)了!
-
這是效果圖
image.png -
onRenderTriggered和onRenderTracked這兩個(gè)都是狀態(tài)跟蹤鉤子函數(shù),跟我們的生命周期函數(shù)的用法是一樣的,他們的作用就是當(dāng)你點(diǎn)擊或者是頁(yè)面上的數(shù)據(jù)發(fā)生改變就會(huì)進(jìn)行觸發(fā),區(qū)別就是onRenderTriggered只會(huì)將當(dāng)前觸發(fā)的打印出來(lái),并且會(huì)顯示新的value值和舊的value值,onRenderTracked是會(huì)將所有發(fā)生改變的數(shù)據(jù)都會(huì)打印出來(lái)
// 這是狀態(tài)觸發(fā),就是你點(diǎn)擊或者是那個(gè)數(shù)據(jù)變化,就會(huì)打印出來(lái),只有當(dāng)前觸發(fā)的,會(huì)將新的value值和舊的value都打印
// 相比下面的鉤子函數(shù),這個(gè)更精準(zhǔn)一些
onRenderTriggered((e)=>{
console.log(e);
})
// 狀態(tài)跟蹤鉤子函數(shù),只要頁(yè)面上的數(shù)據(jù)發(fā)生改變就會(huì)進(jìn)行觸發(fā)
onRenderTracked((event)=>{
console.log(event);
});
-
Suspense--初始異步請(qǐng)求組件
- 1、提供兩個(gè)template的位置,一個(gè)是沒(méi)有請(qǐng)求回來(lái)時(shí)顯示的內(nèi)容,一個(gè)是全部請(qǐng)求完畢的內(nèi)容。
-
2、注意點(diǎn):如果你要使用Suspense的話,要返回一個(gè)promise對(duì)象,而不是原來(lái)的那種JSON對(duì)象。
- 3、接下來(lái)就看看具體怎么實(shí)現(xiàn)吧,先新建一個(gè)模板,components下新建一個(gè)AsyncShow.vue
<template>
<mark>異步請(qǐng)求組件練習(xí)</mark>
<b>{{result}}</b>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup() {
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({ result: "JSPang" });
}, 2000);
});
},
});
</script>
- 4、在我們的一個(gè)組件中進(jìn)行注冊(cè)使用
<template>
<div>
<mark>suspense練習(xí)</mark>
<Suspense>
<template #default>
<AsyncShow></AsyncShow>
</template>
<template #fallback>
<h1>loading.....</h1>
</template>
</Suspense>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import AsyncShow from '../components/AsyncShow.vue'
export default defineComponent({
name:'suspense',
components:{
AsyncShow
}
})
</script>
- 5、他有兩個(gè)template插槽,#default默認(rèn)是數(shù)據(jù)加載后顯示的內(nèi)容,#fallback是我們?cè)诩虞d的時(shí)候,顯示的內(nèi)容,也就是加載的時(shí)候顯示loading。。,加載后顯示數(shù)據(jù)
-
使用getCurrentInstance這個(gè)api可以完美的在頁(yè)面中使用vuex和router,上面使用的useRouter和useStore也是可以進(jìn)行正常的獲取數(shù)據(jù)的
image.png
image.png
-
全局注冊(cè)組件,局部注冊(cè)跟我們vue2.0中的寫(xiě)法是一樣的
-
先在components文件下新建.vue文件,在main.js中進(jìn)行引入,然后看下面的圖片
image.png -
getCurrentInstance----->vue3.0中的這個(gè)API有點(diǎn)牛掰啊,不僅可以通過(guò)他獲取到router中的數(shù)據(jù),還可以獲取到store中的數(shù)據(jù),還可以獲取到全局的變量,首先我們?cè)趍ain.js中進(jìn)行全局變量的書(shū)寫(xiě)
image.png
-
在頁(yè)面中,進(jìn)行獲取到全局變量,先引入這個(gè)api,在onMounted生命周期中打印的就是全局的變量值
image.png 在頁(yè)面上還可以簡(jiǎn)單的進(jìn)行獲取全局的變量
const {
ctx
} = getCurrentInstance();
console.log( ctx ) ; //我們可以將ctx進(jìn)行打印,會(huì)發(fā)現(xiàn)他的下面有這個(gè)mes的變量
console.log(ctx.mes);//可以直接這么簡(jiǎn)寫(xiě),這樣就獲取到了我們?nèi)值淖兞苛?
-
補(bǔ)充:1.watchEffect是監(jiān)聽(tīng)屬性中的一種,叫副作用,可以再頁(yè)面渲染之前就會(huì)進(jìn)行監(jiān)聽(tīng)觸發(fā),刷新的時(shí)候,會(huì)在所有的組件update之前進(jìn)行觸發(fā),他有一個(gè)返回值,可以滿足一定的條件之后進(jìn)行停止監(jiān)聽(tīng),要想在組件更新后繼續(xù)觸發(fā)的話,那么我們就需要進(jìn)行一些操作了,可以在onMounted生命周期中進(jìn)行副作用監(jiān)聽(tīng),也可以加個(gè)屬性,副作用監(jiān)聽(tīng)有兩個(gè)參數(shù),第一個(gè)是回調(diào)函數(shù),第二個(gè)是可以讓副作用在組件更新后繼續(xù)觸發(fā)
const count = ref(0);
const add = () =>{
count.value++;
if(count.value ==4){
stop()//當(dāng)值為4的時(shí)候,停止進(jìn)行觸發(fā)監(jiān)聽(tīng)
}
}
const stop = watchEffect(()=>{ console.log(count.value)})
return { count, add}
//===========
onMounted(()=>{
watchEffect(()=>{ console.log(count.value)})
})
//==========
watchEffect(()=>{
console.log(count.value)
}, {
flush: 'post'//post或者是sync
})
-
補(bǔ)充2:在我們之前使用編程式導(dǎo)航的時(shí)候,router是傳值,route是獲取值,那么在vue-router中有兩個(gè)API,可以進(jìn)行獲取和傳值的
import { useRoute, useRouter } from 'vue-router'
- 可以打印一下就知道怎么用了,跟我們vue2.0中的用法差不多
兄弟組件之間的傳值,我們只能使用外部的插件了
如: mitt 或 tiny-emitter。
-
上面是我重新又用了一遍,發(fā)現(xiàn)沒(méi)有什么問(wèn)題,如果你在練習(xí)中,遇到了什么問(wèn)題,歡迎留言!