博客地址:https://ainyi.com/98

Vue3.0,One Piece

接下来得抽空好好学习了

尤大在 Vue 3.0 beta 直播中推荐了 vite 的工具,强调:针对Vue单页面组件的无打包开发服务器,可以直接在浏览器运行请求的 vue 文件
很新颖,这篇博客用它来搭建一个 vue3 的项目试试

Vite 是面向现代浏览器,基于原生模块系统 ESModule 实现了按需编译的 Web 开发构建工具。在生产环境下基于 Rollup 打包

  • 快速冷启动服务器
  • 即时热模块更换(HMR)
  • 真正的按需编译

node >= 10.16.0

使用 vite 搭建项目

  1. npm init vite-app <project-name>

安装 typescript、vue-router@next、axios、eslint-plugin-vue、sass 等相关插件

vite.config.ts 相当于 @vue-cli 项目中的 vue.config.js

我这简单配置一下:

  1. import path from 'path'
  2. module.exports = {
  3. alias: {
  4. '/@/': path.resolve(__dirname, './src')
  5. },
  6. optimizeDeps: {
  7. include: ['lodash']
  8. },
  9. proxy: {}
  10. }

在 src 下新建 router 文件夹,并在文件夹内创建 index.ts

  1. import { createRouter, createWebHistory } from 'vue-router'
  2. const routes = [
  3. {
  4. path: '/',
  5. name: 'Home',
  6. component: () => import('/@/views/Home.vue')
  7. },
  8. {
  9. path: '/lifeCycle',
  10. name: 'lifeCycle',
  11. component: () => import('/@/views/LifeCycle.vue')
  12. }
  13. ]
  14. export default createRouter({
  15. history: createWebHistory('/krry/'),
  16. routes
  17. })

项目根目录下新建 tsconfig.json 写入相关配置

  1. {
  2. "compilerOptions": {
  3. ...// 其他配置
  4. "paths": {
  5. "/@/*": [
  6. "src/*"
  7. ]
  8. },
  9. "lib": [
  10. "esnext",
  11. "dom",
  12. "dom.iterable",
  13. "scripthost"
  14. ]
  15. },
  16. "include": [
  17. "src/**/*.ts",
  18. "src/**/*.tsx",
  19. "src/**/*.vue",
  20. "src/types/images.d.ts",
  21. "tests/**/*.ts",
  22. "tests/**/*.tsx"
  23. ],
  24. "exclude": [
  25. "node_modules"
  26. ]
  27. }

src 目录下新建 types 文件夹,里面需要配置 ts 的类型

shims-vue.d.ts

  1. declare module '*.vue' {}

images.d.ts

  1. declare module '*.svg'
  2. declare module '*.png'
  3. declare module '*.jpg'
  4. declare module '*.jpeg'
  5. declare module '*.gif'
  6. declare module '*.bmp'
  7. declare module '*.tiff'
  1. import { createApp } from 'vue'
  2. import router from '/@/router'
  3. import App from '/@/App.vue'
  4. const app = createApp(App)
  5. app.use(router)
  6. app.mount('#app')

然后就可以快乐地写代码了

vue3 中用 setup 函数整合了所有的 api;只执行一次,在生命周期函数前执行,所以在 setup 函数中拿不到当前实例 this,不能用 this 来调用 vue2 写法中定义的方法

它将接受两个参数:props、context

  1. // props - 组件接受到的属性 context - 上下文
  2. setup(props, context) {
  3. return {
  4. // 要绑定的数据和方法
  5. }
  6. }

props
setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新
但是,因为 props 是响应式的,不能使用 ES6 解构,因为它会消除 prop 的响应性

如果需要解构 prop,可以通过使用 setup 函数中的 toRefs 来安全地完成此操作

  1. import { toRefs } from 'vue'
  2. setup(props) {
  3. const { title } = toRefs(props)
  4. console.log(title.value)
  5. }

context
context 暴露三个组件的 property:{ attrs, slots, emit }
它是一个普通的 JavaScript 对象,不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构

通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子

因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们
换句话说,在这两个钩子中编写的任何代码都应该直接在 setup 函数中编写

  1. setup() {
  2. onMounted(() => {
  3. console.log('组件挂载')
  4. })
  5. onUnmounted(() => {
  6. console.log('组件卸载')
  7. })
  8. onUpdated(() => {
  9. console.log('组件更新')
  10. })
  11. onBeforeUpdate(() => {
  12. console.log('组件将要更新')
  13. })
  14. onActivated(() => {
  15. console.log('keepAlive 组件 激活')
  16. })
  17. onDeactivated(() => {
  18. console.log('keepAlive 组件 非激活')
  19. })
  20. return {}
  21. }

ref 可以将某个普通值包装成响应式数据,仅限于简单值,内部是将值包装成对象,再通过 defineProperty 来处理的
通过 ref 包装的值,取值和设置值的时候,需用通过 .value来进行设置
可以用 ref 来获取组件的引用,替代 this.$refs 的写法

reactive 对复杂数据进行响应式处理,它的返回值是一个 proxy 对象,在 setup 函数中返回时,可以用 toRefs 对 proxy 对象进行结构,方便在 template 中使用

使用如下:

  1. <template>
  2. <div>
  3. <div>
  4. <ul v-for="ele in eleList" :key="ele.id">
  5. <li>{{ ele.name }}</li>
  6. </ul>
  7. <button @click="addEle">添加</button>
  8. </div>
  9. <div>
  10. <ul v-for="ele in todoList" :key="ele.id">
  11. <li>{{ ele.name }}</li>
  12. </ul>
  13. <button @click="addTodo">添加</button>
  14. </div>
  15. </div>
  16. </template>
  17. <script>
  18. import { ref, reactive, toRefs } from 'vue'
  19. export default {
  20. setup() {
  21. // ref
  22. const eleList = ref([])
  23. function addEle() {
  24. let len = eleList.value.length
  25. eleList.value.push({
  26. id: len,
  27. name: 'ref 自增' + len
  28. })
  29. }
  30. // reactive
  31. const dataObj = reactive({
  32. todoList: []
  33. })
  34. function addTodo() {
  35. let len = dataObj.todoList.length
  36. dataObj.todoList.push({
  37. id: len,
  38. name: 'reactive 自增' + len
  39. })
  40. }
  41. return {
  42. eleList,
  43. addEle,
  44. addTodo,
  45. ...toRefs(dataObj)
  46. }
  47. }
  48. }
  49. </script>
  1. // computed
  2. let sum = computed(() => dataObj.todoList.length + eleList.value.length)
  3. console.log('setup引用computed要.value:' + sum.value)
  4. // watch
  5. watch(
  6. eleList,
  7. (curVal, oldVal) => {
  8. console.log('监听器:', curVal, oldVal)
  9. },
  10. {
  11. deep: true
  12. }
  13. )

响应式地跟踪函数中引用的响应式数据,当响应式数据改变时,会重新执行函数

  1. const count = ref(0)
  2. // 当 count 的值被修改时,会执行回调
  3. const stop = watchEffect(() => console.log(count.value))
  4. // 停止监听
  5. stop()

还可以停止监听,watchEffect 返回一个函数,执行后可以停止监听

与 vue2 一样:

  1. const unwatch = this.$watch('say', curVal => {})
  2. // 停止监听
  3. unwatch()
  1. import {useRoute, useRouter} from 'vue-router'
  2. const route = useRoute() // 相当于 vue2 中的 this.$route
  3. const router = useRouter() // 相当于 vue2 中的 this.$router
  4. route 用于获取当前路由数据
  5. router 用于路由跳转

使用 useStore 来获取 store 对象 从 vuex 中取值时,要注意必须使用 computed 进行包装,这样 vuex 中状态修改后才能在页面中响应

  1. import {useStore} from 'vuex'
  2. setup(){
  3. const store = useStore() // 相当于 vue2 中的 this.$store
  4. store.dispatch() // 通过 store 对象来 dispatch 派发异步任务
  5. store.commit() // commit 修改 store 数据
  6. let category = computed(() => store.state.home.currentCagegory
  7. return { category }
  8. }

博客地址:https://ainyi.com/98

版权声明:本文为ainyi原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/ainyi/p/13927377.html