vue3.0 beta已出,来快速实践一下吧

本文介绍了Vue3.0 Beta的发布,并通过实践讲解了如何创建项目、初始化第一个Vue3程序,包括实例化、setup、ref、reactive、toRefs、计算属性、监听器、DOM操作、组件通信等。还探讨了Vue3的响应式变化、自定义渲染器和对TypeScript的深度支持。
摘要由CSDN通过智能技术生成

vue3.0 beta已出,来快速实践一下吧

本节源码立即前往

前段时间尤大在哔哩哔哩直播了vue3的预览,来简单实践一下吧

vue3的改变

  • 更小更快
  • 支持自定义渲染器
  • 响应式修改为基于Proxy的侦测
  • 深度结合typescript
  • 基于treeshaking优化

创建项目😄

引入文件

克隆一个官方仓库

git clone https://github.com/vuejs/vue-next.git

打开这个项目,下载一下依赖,然后编译

npm i
npm run dev

编译文件在vue-next\packages\vue\dist,可以把它复制出来放到我们创建的项目文件夹

vue-next\packages\vue\examples目录下有官方的示例

脚手架创建项目

首先确保你的@vue/cli为最新版本 vue -V

image-20200516184602081

然后使用 vue create vue3demo创建一个vue项目,创建的时候勾选 vuex router

然后进入项目文件夹,命令行安装插件vue add vue-next将项目升级到vue3,打开package.json可以发现都升级到了最新版本

image-20200517185314922

初始化你的第一个vue3程序⭐️

实例化

为了体验整个api的变化,我们先使用直接引入的方式体验效果,新建一个index.html 引入vue.global.js

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.global.js"></script>
</head>

<body>
</body>

</html>

然后我们新建一个盒子用来挂载vue实例,新建一个模板当做根节点

<body>
    <div id='app'>
    </div>
    <template id="root">
        <div>
        </div>
    </template>
</body>

实例化一个vue3vue3是按需引入,使用一个api之前需要先引入,通过createApp来实例化

<script>
    const {
        createApp
    } = Vue;
    const root = {
        template: '#root',
    }
    createApp(root).mount('#app');
</script>

setup

setup 函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点。

vue3将更多的方法和数据在 setup函数中定义,这就是大家都觉得像react hook 的原因,其实实现的原理是不同的,只是写法有点像;这样做的目的就是为了更好的实现逻辑复用,具体会在后面举例

与 2.x 版本生命周期相对应的组合式 API

  • beforeCreate -> 使用 setup()
  • created -> 使用 setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

setup最后返回所有的对象和方法,注意这里的msg不是响应式对象

const root = {
    template: '#root',
    // beforeCreate  created data和methods 
    setup() {
        console.log('vue init');
        const msg = "vue init";
        return {
            msg
        };
    },
}
<template id="root">
    <div>
        {{msg}}
    </div>
</template>

image-20200518113936084

ref和reactive

refreactive都是用来创建响应式对象的,接下来的案例都使用脚手架创建项目来进行测试

打开views/Home.vue文件,删除掉无用的东西,首先引入ref, reactive

import { ref, reactive } from "vue";
export default {
  name: "Home",
  setup() {
    // 定义一个ref响应式对象
    const count = ref(0);
    // 如果要定义多个可以使用reactive
    const state = reactive({
      size: 36,
      color: "red"
    });
    // 定义一个方法
    const increment = () => {
      count.value++;
    };

    return {
      count,
      increment,
      state
    };
  }
};

在页面中的使用和vue2是一样的

<template>
  <div>
    <div>{{count}}</div>
    <button @click="increment">increment</button>
    <div :style="{fontSize:state.size+'px',color:state.color}">reactive</div>
  </div>
</template>

1

toRefs

上面reactive的导出和使用,必须state.key,如果想像vue2中的data一样定义直接使用,可以使用 toRefs

引入 import { ref, reactive, toRefs } from "vue";,使用 toRefs返回展开对象,如果你不使用toRefs而直接返回对象,原对象的响应式将丢失。

return {
  count,
  increment,
  ...toRefs(state)
};

页面中使用

<div :style="{fontSize:size+'px',color:color}">reactive</div>

image-20200518133238814

计算属性和监听器

我们来到about.vue中进行代码编写,首先引入需要使用的

import { reactive, watch, computed, toRefs, watchEffect } from "vue";

watchEffect 传入一个函数并立即执行,如果函数里面使用了上面定义好的响应式对象,当对象发生变化时,会再次触发这个函数

定义计算属性和监听器

export default {
  setup() {
    const state = reactive({
      num1: 1,
      //定义一个计算属性
      num2: computed(() => state.num1 * 2)
    });
    
    // 如果响应性的属性有变更,就会触发这个函数,但他是惰性的
    watchEffect(() => {
      console.log(`effect 触发了!${state.num1}`);
    });

    // 定义一个监听器
    const stop = watch(state, (val, oldVal) => {
      console.log("watch ", oldVal.num1);
    });

    //数值增加方法
    const increment = () => state.num1++;

    // 停止监听
    const stopwatch = () => stop();

    return {
      ...toRefs(state),
      stopwatch,
      increment
    };
  }
};

查看效果

3

dom操作

components文件夹下新建一个DomRef.vue文件,定义一个空的ref响应数据refdemo并返回,页面中使用ref标签来绑定这个数据,然后就可以通过操作这个响应数据来操作dom

<template>
  <div>
    <div ref="refdemo">domref</div>
    <input type="range" v-model="size" />
  </div>
</template>
<script>
import { ref, watch, onMounted } from "vue";
export default {
  setup() {
    // 定义空白ref作为Template ref操作 dom
    const refdemo = ref(null);
    const size = ref(24);
    // 监听拖动 
    watch(size, (val, oldVal) => {
      refdemo.value.style.fontSize = size.value + "px";
    });
    return {
      refdemo,
      size
    };
  }
};
</script>

home组件中使用这个组件查看效果

<DomRef></DomRef>
...
import DomRef from "../components/DomRef";
...
components: {
  HelloWorld,
  DomRef,
},

看看效果

4

组件通信

和vue2的通信大同小异,新建ComDemo.vue,setup函数接受一个 propscontext 上下文

父组件>>子组件
  • 父组件触发子组件事件
  • 父组件得到子组件属性
  • props传值
<template>
  <div>{{name}}</div>
</template>
<script>
import { inject } from "vue";
export default {
  props: {
    name: String
  },
  setup(props, context) {
    // setup中使用 prop
    console.log("props.name:" + props.name);
    // 供父组件测试
    const str = "我是子组件的str属性";
    const talk = () => {
      console.log("我被父组件触发了");
    };
    return {
      str,
      talk
    };
  }
};
</script>

来的Home.vue中使用这个组件,并给这个子组件绑定一个响应式的ref属性

<ComDemo :name="'我是父组件传值'" @talk="talk" ref="comdemo"></ComDemo>
import ComDemo from "../components/ComDemo";
...
components: {
  HelloWorld,
  DomRef,
},
 ...
setup() {
  // 定义一个ref响应式对象
  const comdemo = ref(null);
  onMounted(() => {
    //得到子组件的值
    console.log(comdemo.value.str);
    // 触发子组件事件
    comdemo.value.talk();
  });
  return {
  	...
    comdemo
  };
}

看看效果

image-20200519162552547

子组件>>父组件

绑定一个方法给子组件

<ComDemo :name="'我是父组件传值'" @talk="talk" ref="comdemo"></ComDemo>
...
setup() {
const talk = e => {
  console.log(e);
};
...
return {
 ...
  talk,
  comdemo
};
...

ComDemo.vue

setup(props, context) {
  ...
  // setup中触发父组件事件
  context.emit("talk", "我是子组件 我触发你了");
  ...
  return {
    str,
    talk
  };
}

效果

image-20200519163223419

inject和provide

这个和vue2使用一样

父组件定义

import { provide } from "vue";
...
provide("injectmsg", "provide talk");

后代组件使用

import { inject } from "vue";
...
const injectmsg = inject("injectmsg");
console.log("injectmsg :>> ", injectmsg);

组合式api示例❤️

前面说到 Composition API的好处,这来举一个例

放一个尤大神的demo,这是一段鼠标操作的功能代码,我们自己还需要编写一个功能来实现结合

const useMouse = () => {
  const state = reactive({
    x: 0,
    y: 0
  });
  const update = e => {
    state.x = e.pageX;
    state.y = e.pageY;
  };
  onMounted(() => {
    window.addEventListener("mousemove", update);
  });
  onUnmounted(() => {
    window.removeEventListener("mousemove", update);
  });
  return toRefs(state);
};

我们再写一个键盘方法,记录每次用户按下键盘

// 监控键盘事件
const useKeyBoard = () => {
  const status = ref(false);
  const update = () => {
    status.value = !status.value;
  };
  onMounted(() => {
    window.addEventListener("keypress", update);
  });
  onUnmounted(() => {
    window.removeEventListener("onkeydown", update);
  });
  return {
    status
  };
};

我们来到 HelloWorld.vue组件中使用这两个方法

<template>
  <div>{{status?`${x}-${y}`:`${y}-${x}`}}</div>
</template>

<script>
import { reactive, onMounted, onUnmounted, toRefs, ref } from "vue";
// 返回鼠标位置
const useMouse = () => {
  const state = reactive({
    x: 0,
    y: 0
  });
  const update = e => {
    state.x = e.pageX;
    state.y = e.pageY;
  };
  onMounted(() => {
    window.addEventListener("mousemove", update);
  });
  onUnmounted(() => {
    window.removeEventListener("mousemove", update);
  });
  return toRefs(state);
};
// 监控键盘事件
const useKeyBoard = () => {
  const status = ref(false);
  const update = () => {
    status.value = !status.value;
  };
  onMounted(() => {
    window.addEventListener("keypress", update);
  });
  onUnmounted(() => {
    window.removeEventListener("onkeydown", update);
  });
  return {
    status
  };
};
export default {
  name: "HelloWorld",
  setup() {
    return {
      ...useMouse(),
      ...useKeyBoard()
    };
  }
};
</script>

我们在页面中显示鼠标方位,当我们按下任何按键的时候,这个显示颠倒

看下效果

5

vuexvuerouter💥

vuexvuerouter在实例化方式上有了一点区别,分别使用 createStorecreateRouter进行实例化

使用vuex

打开vue3demo\src\store\index.js文件

import Vuex from 'vuex'

export default Vuex.createStore({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
      console.log('当前count:',state.count);
    }
  },
  actions: {},
  modules: {}
});

新建一个 RouterAndVuex.vue组件

<template>
  <div>
    <button @click="increment">increment</button>
  </div>
</template>

<script>
import { useStore } from "vuex";
export default {
  setup() {
    const store = useStore();
    const count = store.state.count;
    console.log("vuex >>", count);
    const increment = () => {
      // mutations
      store.commit("increment");
    };
    return {
      increment,
    };
  }
};
</script>

看看效果

6

使用vuerouter

<template>
  <div>
    <button @click="increment">increment</button>
    <button @click="gotoAbout">about</button>
  </div>
</template>

<script>
import { useStore } from "vuex";
import { useRouter } from "vue-router";
export default {
  setup() {
    //   使用vuex
    const store = useStore();
    const count = store.state.count;
    console.log("vuex >>", count);
    const increment = () => {
      // mutations
      store.commit("increment");
    };
    // 使用vue-router
    const router = useRouter();
    const gotoAbout = () => {
      router.push("About");
    };
    return {
      increment,
      gotoAbout
    };
  }
};
</script>

看看效果

7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值