vue3.0的基礎(chǔ)語(yǔ)法

  • 新修改獲取全局變量的簡(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)題,歡迎留言!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。