vue3.0学习笔记

文章大部分的内容是看了技术胖的视频写的,有的也是贴的他的注解,感谢技术胖

搭建项目

vuecli搭建

安装vue-cli 须(v4.5.4以上版本),低版本自行更新

npm install -g @vue/cli

快速生成项目

vue create 项目名称

根据自己需要选择,如果想要ts,选择第三项

? Please pick a preset: (Use arrow keys)            //请选择预选项
> Default ([Vue 2] babel, eslint)                   //使用Vue2默认模板进行创建
  Default (Vue 3 Preview) ([Vue 3] babel, eslint)   //使用Vue3默认模板进行创建
  Manually select features                          //手动选择(自定义)的意思

空格键根据自己需要来进行选择,加上一个ts

? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Choose Vue version
 (*) Babel
 (*) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
 ( ) Vuex
 ( ) CSS Pre-processors             //CSS预处理器
 (*) Linter / Formatter             //格式化工具
 ( ) Unit Testing                   //单元测试
 ( ) E2E Testing                    //E2E测试

选择3.x的版本

? Choose a version of Vue.js that you want to start the project with (Use arrow keys)
> 2.x
  3.x (Preview)

我还不知道这个语法具体是干什么的,后面再补充吧,先选n

Use class-style component syntax?

是否使用TypeScript和Babel的形式编译 JSX.选n,没有写jsx什么的

Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n)

eslint配置,先选第一项,有需要自己再配

? Pick a linter / formatter config: (Use arrow keys)
> ESLint with error prevention only
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier
  TSLint (deprecated)

lint的特性,有需要fix就选fix,自己配,我先选只校验

? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Lint on save         //保存的时候进行Lint
 ( ) Lint and fix on commit   //需要帮你进行fix(修理),这项我们不进行选择

配置文件是否单独存放,我们选单独存放

Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files

需不需要把这些配置保存下来,下次好直接进行使用。自己看情况选择,我选n

Save this as a preset for future projects? (y/N)

然后安装再起项目就可以了

npm run serve

文件类目

|-node_modules       -- 所有的项目依赖包都放在这个目录下
|-public             -- 公共文件夹
---|favicon.ico      -- 网站的显示图标
---|index.html       -- 入口的html文件
|-src                -- 源文件目录,编写的代码基本都在这个目录下
---|assets           -- 放置静态文件的目录,比如logo.pn就放在这里
---|components       -- Vue的组件文件,自定义的组件都会放到这
---|App.vue          -- 根组件,这个在Vue2中也有
---|main.ts          -- 入口文件,因为采用了TypeScript所以是ts结尾
---|shims-vue.d.ts   -- 类文件(也叫定义文件),因为.vue结尾的文件在ts中不认可,所以要有定义文件
|-.browserslistrc    -- 在不同前端工具之间公用目标浏览器和node版本的配置文件,作用是设置兼容性
|-.eslintrc.js       -- Eslint的配置文件,不用作过多介绍
|-.gitignore         -- 用来配置那些文件不归git管理
|-package.json       -- 命令配置和包管理文件
|-README.md          -- 项目的说明文件,使用markdown语法进行编写
|-tsconfig.json      -- 关于TypoScript的配置文件
|-yarn.lock          -- 使用yarn后自动生成的文件,由Yarn管理,安装yarn包时的重要信息存储到yarn.lock文件中,不使用就没有

钩子和Api

setup和ref

setup 函数的用法,可以代替 Vue2 中的 date 和 methods 属性,直接把逻辑写在 setup 里就可以
使用setup()语法就不用写data了,一开始用不习惯,在setup里声明的变量,需要return才可以在页面中使用

<template>
<div>
  <img alt="Vue logo" src="./assets/logo.png" />
  <button v-for="(item, index) in boys" v-bind:key="index" @click="toSelectboy(index)">
    {{ index }} : {{ item }}
  </button>
  <div>你选择踢【{{ selectedBoy }}】一脚</div>
</div>
</template>

<script lang="ts">
import {
  defineComponent,
  ref
} from "vue";

export default defineComponent({
  name: "App",
  setup() {
    const boys = ref(["渣虎", "渣辉", "渣茂"]);
    const selectedBoy = ref("");
    const toSelectboy = (index: number) => {
      selectedBoy.value = boys.value[index];
    };
    return {
      boys,
      selectedBoy,
      toSelectboy
    };
  },
  components: {},
});
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

在setup里声明的变量,想响应式需要用ref包裹一下,但是每次获取变量值的时候,并不能直接拿到这个值,需要.value,这样就很麻烦,我们来用reactive优化一下

reactive

reactive接受的参数是一个object,把要声明的变量都作为object的属性

<template>
<div>
  <button v-for="(item, index) in data.boys" v-bind:key="index" @click="data.toSelectboy(index)">
    {{ index }} : {{ item }}
  </button>
  <div>你选择踢【{{ data.selectedBoy }}】一脚</div>
</div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  ref
} from "vue";

export default defineComponent({
  name: "App",
  setup() {

    const data = reactive({
      boys: ["渣虎", "渣辉", "渣茂"],
      selectedBoy: "",
      toSelectboy: (index: number) => {
        data.selectedBoy = data.boys[index];
      }
    })
    // const boys = ref(["渣虎", "渣辉", "渣茂"]);
    // const selectedBoy = ref("");
    // const toSelectboy = (index: number) => {
    //   selectedBoy.value = boys.value[index];
    // };
    return {
      data
    };
  },
  components: {},
});
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

但是如果这样写的话,页面上每个变量前面都要加上data,所以我们再优化一下,(注意,返回时直接用拓展运算符去展开data是没有用的,那样返回的就是普通的变量,不能再具有响应式的能力)

使用 toRefs

<template>
<div>
  <button v-for="(item, index) in boys" v-bind:key="index" @click="toSelectboy(index)">
    {{ index }} : {{ item }}
  </button>
  <div>你选择踢【{{ selectedBoy }}】一脚</div>
</div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  ref,
  toRefs
} from "vue";

export default defineComponent({
  name: "App",
  setup() {

    const data = reactive({
      boys: ["渣虎", "渣辉", "渣茂"],
      selectedBoy: "",
      toSelectboy: (index: number) => {
        data.selectedBoy = data.boys[index];
      }
    })
    const refData = toRefs(data);
    return {
      ...refData
    };
  },
  components: {},
});
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

这样就可以再页面上直接用变量了,我们再优化一下,加上类型注解

<template>
<div>
  <button v-for="(item, index) in boys" v-bind:key="index" @click="toSelectboy(index)">
    {{ index }} : {{ item }}
  </button>
  <div>你选择踢【{{ selectedBoy }}】一脚</div>
</div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  toRefs
} from "vue";
interface DataProps {
  boys: string[];
  selectedBoy: string;
  toSelectboy: (index: number) => void;
}
export default defineComponent({
  name: "App",
  setup() {

    const data: DataProps = reactive({
      boys: ["渣虎", "渣辉", "渣茂"],
      selectedBoy: "",
      toSelectboy: (index: number) => {
        data.selectedBoy = data.boys[index];
      }
    })
    const refData = toRefs(data);
    return {
      ...refData
    };
  },
  components: {},
});
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

生命周期


注意:生命周期函数不要用箭头函数(箭头函数没有自己的this,所以可能会报错)

setup里的生命周期钩子

setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
onBeforeMount() : 组件挂载到节点上之前执行的函数。
onMounted() : 组件挂载完成后执行的函数。
onBeforeUpdate(): 组件更新之前执行的函数。
onUpdated(): 组件更新完成之后执行的函数。
onBeforeUnmount(): 组件卸载之前执行的函数。
onUnmounted(): 组件卸载完成后执行的函数
onActivated(): 没用过,技术胖说是被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行。
onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行。
onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数(还没用过)。

const app = {
  name: "App",
  setup() {
    console.log("1-开始创建组件-----setup()");
    const data: DataProps = reactive({
      boys: ["渣虎", "渣辉", "渣茂"],
      selectedBoy: "",
      toSelectboy: (index: number) => {
        data.selectedBoy = data.boys[index];
      }
    })
    onBeforeMount(() => {
      console.log("2-组件挂载到页面之前执行-----onBeforeMount()");
    });

    onMounted(() => {
      console.log("3-组件挂载到页面之后执行-----onMounted()");
    });
    onBeforeUpdate(() => {
      console.log("4-组件更新之前-----onBeforeUpdate()");
    });

    onUpdated(() => {
      console.log("5-组件更新之后-----onUpdated()");
    });

    const refData = toRefs(data);

    return {
      ...refData,
    };
  },
};
export default app;

vue2的钩子函数还是可以继续用的
看一下vue2和vue3的对比


Vue2--------------vue3
beforeCreate  -> setup()
created       -> setup()
beforeMount   -> onBeforeMount
mounted       -> onMounted
beforeUpdate  -> onBeforeUpdate
updated       -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed     -> onUnmounted
activated     -> onActivated
deactivated   -> onDeactivated
errorCaptured -> onErrorCaptured
状态跟踪

onRenderTracked直译过来就是状态跟踪,它会跟踪页面上所有响应式变量和方法的状态,也就是我们用return返回去的值,他都会跟踪。只要页面有update的情况,他就会跟踪,然后生成一个event对象,我们通过event对象来查找程序的问题所在。
引用然后再setup里使用

import { .... ,onRenderTracked,} from "vue";


onRenderTracked((event) => {
  console.log("状态跟踪组件----------->");
  console.log(event);
});
状态触发

onRenderTriggered直译过来是状态触发,它不会跟踪每一个值,而是给你变化值的信息,并且新值和旧值都会给你明确的展示出来。
使用和onRenderTracked一致,event的属性如下

- key 哪个变量发生了变化
- newValue 更新后变量的值
- oldValue 更新前变量的值
- target 目前页面中的响应变量和函数
watch

引入watch

import {... , watch} from "vue"

在setup里实现watch

 watch(要监听的变量, (newValue, oldValue) => {
    要做的事
  });

如果监听reactive变量data里的属性,需要用函数返回的形式,否则会报错

 watch([变量1, () => data.变量], (newValue, oldValue) => {
    console.log(`new--->${newValue}`);
    console.log(`old--->${oldValue}`);
  });

监听多个变量,拿到的回调的值也是一个数组

模块化

模块化ts文件一般放在hooks目录下

新建一个useNowTime.ts文件

import {ref} from "vue";

const nowTime = ref('00:00:00')
const getTime = () => {
  const now = new Date();
  const hour = now.getHours() < 10 ? "0" + now.getHours() : now.getHours()
  const minu = now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes()
  const sec = now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds()
  nowTime.value = hour + ":" + minu + ":" + sec
  console.log(nowTime.value);

}

export {
  nowTime,
  getTime
}

在需要用到的地方引入

import { nowTime, getNowTime } from "./hooks/useNowTime";

记得在setup里一定要return出去,页面才能用

return {nowTime,getNowTime};

当然,模块化里可以封装好暴露一个方法,比如调一个api,然后拿到这个方法的返回值,这里是用的技术胖的链接,哈哈,感谢技术胖

import { ref } from "vue"
import axios from "axios"


function useAxiosUrl(url: string) {

  const result = ref(null)
  const loading = ref(true)
  const loaded = ref(false)
  const error = ref(null)

  axios.get(url).then( (res) => {
    loading.value = false
    loaded.value = true
    result.value = res.data
      }).catch(e => {
        console.log(e);
        loading.value = false
      })

      return {
        result ,
		loading,
		loaded ,
		error 
      }
}
export default useAxiosUrl

页面引入

import useAxiosUrl from "./hooks/useUrlAxios"

使用

    const {
      result,
      loading,
      loaded
    } = useAxiosUrl("https://apiblog.jspang.com/default/getGirl")

记得return

    return {
      result,
      loading,
      loaded
    };

路由

vue2和vue3的对比

生成路由

// vue2
const router = new Router({
    mode: history,
    ...
});
 
// vue3
import {createRouter, createWebHistory} from 'vue-next-router';
const router = createRouter({
    history: createWebHistory(),
    ...
})

base,vue3里传给createWebHistory()的第一个参数为base


// vue2
const router = new Router({
    base: __dirname,
    ...
})
 
// vue3
import {createRouter, createWebHistory} from 'vue-next-router';
const router = createRouter({
    history: createWebHistory(/),
    ...
})
// 导航守卫----vue2
import router from./router‘
router.beforeEach((to, from, next) => {
   // ...
    if (to.matched.length === 0) {
        next('/404')
    } else {
        next()
    }
    //console.log(to, from, next, '路由守卫')
})

//导航守卫----vue3,在app.vue里
import {
    useRouter
} from 'vue-router';
export default {
    name: 'App',
    setup() {
        const router = useRouter();
        router.beforeEach((to, from, next) => {
            // ...
            if (to.matched.length === 0) {
                next('/404')
            } else {
                next()
            }
        })
    }
}

vue2里到一个不存在的路由,除非配置了404,否则会到根页面,而vue3push或者resolve一个不存在的命名路由时,会引发错误,不会导航到根路由,页面空白

替代vuex

还没有看,后面再写

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值