vue3.0的基础语法

  • 新修改获取全局变量的简单的写法,在底部,请进行查看!

  • 首先我们安装vue3.0以上的脚手架全局

  cnpm install @vue/cli -init -g //兼容vue2.0的也可以下
  • 创建项目

  vue create 项目名
  • 此时打开你的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",//这个也是,应该是4. 几的版本
    "vuex": "^3.4.0"//这个也是,应该是4. 几的版本
  },
  • 在命令行输入指令

  vue  add  vue-next
  • 这是在查看版本就好了,还有打开vue-router和vuex文件,创建的方式有点不一样,以前是new 一个 ,现在是创建一个

   "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)//体验vue3.0
  • 此时命令符会提示我们要下载这个插件,进行下载

  cnpm install --save composition-api  //有点记不清了,可以看命令符里面的提示
  • 注意:由于现在是正式版发布了,所以上面的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()">点击</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'//把这个api换成vue也可以
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  setup(){
    const state=reactive({
      title:'hello vue 3.0',
      age:20,
      sex:'男',
      num:computed(()=>100)//计算属性的方法写法
    })
    //方法,要有返回值才会显示
    let dian=()=>{
      state.age+=10;
      console.log(state.age);
    }
    // return state//返回全部的数据
    // return {//返回指定的数据
    //   title:state.title,
    //   age:state.age
    // }
    return {
      ...toRefs(state),//torefs响应式的方法,视图更新
      dian//导出方法,否则视图不更新
    }
    
  }
  // data () {//vue2.0的初始化数据
  //   return{
  //     aa:"hello"
  //   }
  // },
  // methods:{//方法属性
  //   ac(){
  //       let a='bb';
  //       this.aa=a;
  //   }
  // }
}
</script>

<style scoped>

</style>

  • 父传子(provide这个方法传递后,在子组件,孙子组件中都是可以获取到的)

  • 在父组件中
<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:'我是父组件的数据,传递给子组件'
    })
    provide('ac',state.tit);//通过provide传值第一个参数为自定义名,第二个为值
    return{
      ...state //一定要加返回值
    }
  }
}
</script>

  • 在子组件中
{{tit}}
  <script>
import {reactive,toRefs,computed,inject} from '@vue/composition-api'
export default {
  name: 'HelloWorld',
  setup(){
    const tit=inject('ac');//接受传递过来的参数,要return导出去,否则会找不到tit
    const state=reactive({
      title:'hello vue 3.0',
      age:20,
      sex:'男',
      num:computed(()=>100),//计算属性的方法写法
      // tit:inject('tit')//也可以这样接受参数
    })
    //方法,要有返回值才会显示
    let dian=()=>{
      state.age+=10;
      console.log(state.age);
    }
    return {
      ...toRefs(state),//torefs响应式的方法,视图更新
      dian,
      tit
    }
    
  }
}
</script>

  • 路由跳转(getCurrentInstance使用这个API也是可以的哟!)

<button @click="toPage('About')">点击跳转页面</button>
<script>
import {ref} from 'vue'
import {useRouter} from 'vue-router'
export default {
 setup(){
   const name=ref('我是vue3.0尝鲜版本');
   const abc=ref('相当于是一个导出');
   const create=ref(`<p>我是一个p标签</p>`);
   const router=useRouter();//路由跳转
   const toPage=path=>router.push(path);
   return {
     name,abc,create,toPage
   }
 }
}
</script>
  • 监听路由

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(){//这是使用的监听属性
    const title=ref('我是home主页面');
    const route=useRouter();
    * 这是监听路由的第一种写法
    // watch(route.currentRoute,({path})=>{//{path}==》相当于是解构赋值
      // console.log(route.currentRoute.value);
      // console.log(path);
      // const ad = path==='/'?'我是home主页面':'我是about页面';
      // title.value = ad ;
    //   if(path==='/'){
    //     title.value='我是home主页面';
    //   }else{
    //     title.value='我是about页面';
    //   }
    // })
* 这是监听路由的第二种写法(推荐)
    watchEffect(()=>{//比监听watch好用一些,刚开始进入页面就会监听
    console.log(route.currentRoute.value);
      const {path}=route.currentRoute.value;
      const ad = path==='/'?'我是home主页面':'我是about页面';
      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>

  • 计算属性(监听路由的变化)

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(){//使用计算属性进行渲染
    const route=useRouter();
    const title=computed(()=>{
       const {path}=route.currentRoute.value;
      return  path==='/'?'我是home主页面':'我是about页面';
    })
    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>

  • 点击事件

quit()加括号,方法有参数才会执行,要是不加括号,方法有参数,会不执行,打印显示默认参数$event参数
 <button @click="quit()">返回home页</button>
import {useRouter} from 'vue-router';

export default {
    setup(){
      const route=useRouter();
      const quit=(lev=-1)=>route.go(lev);//lev默认值为-1,传值就是当前的值
      return{
        quit
      }
    }
}
  • 传值(相当于是vuex)

  • 先新建一个chaunZhi.js文件
//相当于vuex传值一样
import {ref} from 'vue';
const num1=ref(1000);//这是渲染页面的数字
const dianJi=(num=1)=>{//这是方法
    num1.value+=num;
}
export {//导出
    num1,dianJi
}
  • 在about.vue页面引入
    <p>你被点击了多{{num1}}次</p>
    <button @click="dianJi()">点击</button>
    <script>
      import {num1,dianJi} from '@/components/chaunZhi.js';
      export default {
        setup(){
          return{
            num1,dianJi
          }
        }
    </script>
  • 在app.vue页面中再次引入
     <p>你被点击了{{num1}}次</p>
       <script>
      import {num1} from '@/components/chaunZhi.js';
      export default {
        setup(){
          return{
            num1
          }
        }
    </script>
  • 此时当在about.vue中点击时,在app.vue中会同步显示
  • 使用vuex

  • 在vuex页面跟我们vue2.0的写法是一样的
  • 在页面中使用vuex数据(getCurrentInstance也可以使用这个API,下面有介绍,这个是可以正常输出的)
    import {useStore} from 'vuex';
    export default {
      setup(){
        const store=useStore();
        const pro=computed(()=>store.state.pro);//这是获取state中的值
        const dd=store.commit('dd');//这是调用方法
        let ff=()=>{//这是2020-8-21自己再次练习的时候写的
            store.commit("add")
        }
        return{
          pro,dd
        }
      }
    }
  • 父传子,子传父
  • 跟我们在Vue2.0中的写法是一样的,就是稍微的改变一些
  • 父组件
  list不是动态的传递,所以不需要绑定,注意方法后面不加括号!!!不加括号,否则数据显示undefined
  <History list="我是HOME组件进行传递的数据" @ac="ac"></History>
   setup(){//相当于created或者是beforecreate
    let ac=(k)=>{
      console.log(k);这个参数就是我们的子组件传递给父组件的数据
      }
    },
    return{
      ac//--->一定要将方法return出去,否则会报错的哟!
    }
  • 子组件
   <mark>{{list}}</mark>
    {{b}}
  export default {
    props:['list'],这是接受父组件传递过来的参数,跟Vue2.0一样,在页面上直接写就可以了
    setup(props,ctx){

          /**
       * 父传子,将这个下标传递给子组件中
       */
      let st=reactive({
          num:0
      })
     let chu=()=>{
         st.num++;
        //  console.log(st);
        // console.log(props);
        ctx.emit('ac',st.num);这是点击后,将数据传递给父组件
         console.log(props.list);这是获取到父组件传递过来的值
     }
      修改父组件传递过来的数据
       let a=reactive({
         b:props.list
       });
       a.b='66666'将“我是HOME组件进行传递的数据”改为66666
      provide("chuan",st.num);//不能放到点击事件中,而且值不是动态的,只传递第一次的初始值
     return{
         chu,
         st,
         props,这个写不写都行,但是setup(props)这个要写要不ctx.emit会报错
         ...toRefs(a)
        }
      }
     }
  • 函数式的方式(为满足业务的需求,我们需要写好几百行代码及方法,不能都写在setup中,这样的话后期的维护不好维护,每次都要去找,所以我们可以在函数中写上我们的方法等,最后在setup中return就可以了)
    <p style="color:red;">{{asd.aa.value}}----111</p>这里的asd是setup中return的那个变量
    <p style="color:red;">{{asd.ba.value}}----2222</p>
    <p style="color:red;">{{asd.ads.value.bas}}----ref</p>ads是asd函数中的ref的值可以直接输出asd可以看看返回的数据格式就明白了
    <button @click="asd.bass()">点击修改函数中的变量值{{asd.bass}}</button>方法的后面有没有括号都可以
  <script>
  import { reactive, toRefs , ref } from 'vue'
  function  add() {
    let asd=reactive({
        aa:'我是一个函数',
        ba:"我可以写多个函数,在导出就可以了"
    });
    let ads=ref({
        bas:'我是ref的写法在函数中'
    })
    let bass=()=>{//这是方法,相当于Vue2.0中的methods
        asd.aa="我是点击事件,修改aa为666"
    }
    return{
        ...toRefs(asd),ads,bass
    }
  }
  export default {
    setup(){
       return{
         asd:add(),这里只需要到处一次就可以了,不需要两次
        //  ads:add()
     }
    }
  }
  </script>
  • 上面使用函数的写法有点子low啊,其实可以使用解构赋值的
  function add(){
    let a=reactive({
        b:'我是函数中的变量',
        c:'可以使用解构赋值哦'
    })
    return a;
}
export default {
    setup(){
         直接进行解构赋值就可以了
        let {b,c}=add();
        return{
           c,b
        }
    }
}
  • teleport瞬移组件的使用(以下开始是使用ts+vue3.0进行的练习)
  • 说明:就是之前我们使用全局注册组件还是局部进行注册组件,都是在根组件app下,但是使用了teleport之后,我们可以在新建一个根组件了,相当于有两个及多个根组件,用法都是一样的没有什么改变
  • 1、先新建一个组件,之后再app.vue中进行局部注册,然后进行使用,不过我们要在当前的组件当中添加上这个teleport标签


    image.png
  • 然后在我们写的组件当中
<template>
#Model就是我们添加到根组件的id名
    <teleport to="#Model">
        <mark>1322</mark>
    </teleport>

</template>
  • 还有最后一步哟,找到我们在public下的index.html文件
image.png
  • 这样的话,再去浏览器中看看吧,我们的根组件就会变成两个了!
  • 这是效果图


    image.png
  • onRenderTriggered和onRenderTracked这两个都是状态跟踪钩子函数,跟我们的生命周期函数的用法是一样的,他们的作用就是当你点击或者是页面上的数据发生改变就会进行触发,区别就是onRenderTriggered只会将当前触发的打印出来,并且会显示新的value值和旧的value值,onRenderTracked是会将所有发生改变的数据都会打印出来
// 这是状态触发,就是你点击或者是那个数据变化,就会打印出来,只有当前触发的,会将新的value值和旧的value都打印
    // 相比下面的钩子函数,这个更精准一些
    onRenderTriggered((e)=>{
      console.log(e);
    })
    // 状态跟踪钩子函数,只要页面上的数据发生改变就会进行触发
    onRenderTracked((event)=>{
      console.log(event);
    });
  • Suspense--初始异步请求组件
  • 1、提供两个template的位置,一个是没有请求回来时显示的内容,一个是全部请求完毕的内容。
  • 2、注意点:如果你要使用Suspense的话,要返回一个promise对象,而不是原来的那种JSON对象。
  • 3、接下来就看看具体怎么实现吧,先新建一个模板,components下新建一个AsyncShow.vue
<template>
    <mark>异步请求组件练习</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、在我们的一个组件中进行注册使用
<template>
    <div>
        <mark>suspense练习</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、他有两个template插槽,#default默认是数据加载后显示的内容,#fallback是我们在加载的时候,显示的内容,也就是加载的时候显示loading。。,加载后显示数据
  • 使用getCurrentInstance这个api可以完美的在页面中使用vuex和router,上面使用的useRouter和useStore也是可以进行正常的获取数据的

image.png
image.png
  • 全局注册组件,局部注册跟我们vue2.0中的写法是一样的
  • 先在components文件下新建.vue文件,在main.js中进行引入,然后看下面的图片


    image.png
  • getCurrentInstance----->vue3.0中的这个API有点牛掰啊,不仅可以通过他获取到router中的数据,还可以获取到store中的数据,还可以获取到全局的变量,首先我们在main.js中进行全局变量的书写
image.png
  • 在页面中,进行获取到全局变量,先引入这个api,在onMounted生命周期中打印的就是全局的变量值


    image.png
  • 在页面上还可以简单的进行获取全局的变量

 const {
            ctx
        } = getCurrentInstance();
        console.log( ctx ) ; //我们可以将ctx进行打印,会发现他的下面有这个mes的变量
        console.log(ctx.mes);//可以直接这么简写,这样就获取到了我们全局的变量了
  • 补充:1.watchEffect是监听属性中的一种,叫副作用,可以再页面渲染之前就会进行监听触发,刷新的时候,会在所有的组件update之前进行触发,他有一个返回值,可以满足一定的条件之后进行停止监听,要想在组件更新后继续触发的话,那么我们就需要进行一些操作了,可以在onMounted生命周期中进行副作用监听,也可以加个属性,副作用监听有两个参数,第一个是回调函数,第二个是可以让副作用在组件更新后继续触发
 const count = ref(0);
 const add = () =>{ 
  count.value++;
  if(count.value ==4){
        stop()//当值为4的时候,停止进行触发监听
   }
}
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
  })
  • 补充2:在我们之前使用编程式导航的时候,router是传值,route是获取值,那么在vue-router中有两个API,可以进行获取和传值的

import { useRoute, useRouter } from 'vue-router'

  • 可以打印一下就知道怎么用了,跟我们vue2.0中的用法差不多
兄弟组件之间的传值,我们只能使用外部的插件了

如: mitt 或 tiny-emitter。

  • 上面是我重新又用了一遍,发现没有什么问题,如果你在练习中,遇到了什么问题,欢迎留言!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335