iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >vue3基础知识剖析
  • 773
分享到

vue3基础知识剖析

vue3基础知识vue3基础 2022-11-13 14:11:46 773人浏览 泡泡鱼
摘要

目录声明vue3.0有哪些新特性Vue3.0的优缺点如何解锁vue3.0体验vue3.0的4中姿势核心的composition apisetupsetup语法糖ref、Reactiv

前言

前段时间,由新东方出品直播带货品牌东方甄选火爆全网,其中最受大家关注的主播董宇辉,用网友的调侃来说“长着一个颗粒无收的脸,却拥有五谷丰登的灵魂”。他在直播中推荐五常大米时说:“厨房里充满了饭香,就是人间浪漫。”,介绍水蜜桃:“这个水蜜桃,美好的像穿越大峡谷的风,像仲夏夜的梦”。卖牛排,告诉观众这是“Original Cutting”。让网友赞叹不绝,大家都说这买的不是吃的,买的是知识付费,买的是灵魂洗礼。最重要的是,他尽然还是一个英语老师。很多人感叹,好好读书太重要了,因为知识能给人带来力量,带来高贵的灵魂。相比那些快节奏、声嘶力竭、充满商业诱导的的直播模式,简直就是降维打击

从笔者的角度来看,董宇辉的成功并非偶然,能够饱读诗书,一定源于自己多年不断的思考跟总结,不断的追求学习的本质才能让自己在无意之间沉淀的像个诗人,像个哲学家。这背后的付出,常人肯定无法想象。作家周岭说过“所谓的学习,不是努力,努力,在努力。而是反馈,反馈,再反馈。光靠一味的输入,而不输出,这种学习大概率是低效率的”。就像咱们前端技术圈一样,框架层出不穷,版本迭代快的让人无法喘息。很多小伙伴都焦虑的呐喊,学不动了。笔者认为,真正高效的学习一定是需要在输入的同时,要有很好的输出,让自己积累更多的正向反馈,就像我们平时学习某一种技术栈一样,光是一味的学习不行,还要做出高质量的实践跟输出才行!

笔者这篇文章会从vue3基础的知识点开始剖析,特别是在将composition API的时候,在代码示例中不会一上来就使用setup语法糖,而是用早期的setup函数,这样方便于初学的小伙伴们理解跟学习。文章篇幅较大,接下来,请您花个10分钟耐心的看完,或许会有不一样的收货。

声明

  • 本文中下边所有的示例代码都可以直接访问这个网站点击这里查看效果需要源代码的小伙伴可以在评论区下留言,或者私信我。
  • 本文章的讲解的所有实例面向对vue3的初学者,如有讲解不到位,或者有偏差的地方,欢迎大家留言指出。

vue3.0有哪些新特性

  • Composition Api (最重要的新特性)
  • 组件通信
  • 生命周期
  • 自定义Hook
  • 插槽
  • v-model的更改
  • 更加纯粹的Tree-shaking
  • 配合状态管理的Pinia
  • 配合升级的vue-router 4.x
  • 配合升级的打包工具vite
  • 配合TS在项目中自由使用

vue3.0的优缺点

优点

  • 使用vue3最大的优势个人认为倒不是它的Api,而是配合使用的vite打包工具,特别是大型项目本地启动要比当前的webpack5要快至少2倍以上(项目中测试过)
  • 比起vue 2.xComposition Api的优势要明显的多,如果习惯了setup语法糖的写法,你会发现爽的飞起,很多之前在vue 2.x中大量重复逻辑不存在了
  • 底层通过Proxy来实现双向绑定,性能上提升了很多
  • TypeScript支持度更好,可以很愉快的在项目中使用TypeScript

缺点

  • 如果还有IE情节的公司,那vue3确实不太适合,因为vue3已经抛弃了对IE11的支持,再说了 微软人家自己都不打算维护IE了,兄弟们,放弃IE拥抱chrome吧!
  • Composition Api的写法需要花一点点时间来适应,毕竟学习新语法还是需要成本的

如何解锁vue3.0

体验vue3.0的4中姿势

  • 通过CDN
<script src="https://unpkg.com/vue@next"></script>
  • npm
# 最新稳定版
npm install vue@next
npm install -D @vue/compiler-sfc

如果你是从Vue 2.x升级的,请注意 @vue/compiler-sfc 替换掉了 vue-template-compiler

  • vue-cli
npm install -g @vue/cli
vue upgrade --next
  • vite
npm init vite@latest <project-name> -- --template vue
cd <project-name>
npm install
npm run dev

推荐使用第4种方式,直接使用官方推荐最新的vite打包工具,直接初始化项目。

核心的composition API

setup

  • setupvue3提出的一个非常重要的选项,也是Composition Api最为核心的语法之一。
  • setup执行时机是在beforeCreate之前执行的。
  • setup返回的是一个对象,对象中的所有属性都是可以在template中使用
  • setup中不能使用this
  • setup中注册生命周期onMountedwatchcomputed等,我们会在下边详细讲解

setup参数

  • props
  • context
<script>
export default {
  setup (props, context) {
    return {}
  }
}
</script>

setup语法糖

既然上边提到了setup语法,那就有必要把setup语法糖介绍一下,我们在实际的项目开发中在熟悉了setup语法的本质后,也推荐大家使用setup语法糖来编写,这样也可以大大提升开发效率。

  • 不需要像上述一样return,只需要在<script setup>中声明一下即可
  • 任何在 <script setup> 声明的顶层的绑定 (包括声明的变量,函数声明,以及 import 引入的内容) 都可以在模板中直接使用
  • 组件在语法糖中可以自动注册,无需再通过components进行注册
<script setup>
import {ref} from 'vue'
let property = ref('这里是响应式属性');
// 这里我们引入了子组件SetUp.vue
import SetUp from '@/components/SetUp.vue'
</script>

ref、reactive

  • refreactive都是vue3中用来做数据定义使用的,如同vue2中在data中做数据定义一样,示例代码如下:
<template>
    <h3>{{ state.count }}</h3>
    <h3>{{ num }}</h3>
    <el-button @click="handleAdd" type="primary">ref计算</el-button>
</template>

<script>
import { ref, reactive } from 'vue'

export default {
    setup() {
        const num = ref(0)
        const state = reactive({ count: 1 })
        function handleAdd() {
            state.count++;
            num.value += 2;
        }
        return {
            state,
            num,
            handleAdd
        }
    }
}
</script>
  • refreactive的区别在哪呢?很多人分不清楚,网上有很多文章简单的定义为ref负责处理基本数据类型的双向绑定,reactive负责处理对象的双向绑定。其实,这样笔者会觉得给很多初学者带来很多误导,其实ref也可以处理对象的双向绑定,就像下边这段代码一样。
<template>
    <el-button @click="handleAdd" type="primary">ref计算</el-button>
    <h3>{{ obj.count }}</h3>
</template>

<script>
export default {
    setup() {
        // ref 对象双向绑定
        const obj = ref({ count: 1 })
        function handleAdd() {
            obj.value.count = obj.value.count + 1
        }
        return {
            obj,
            handleAdd
        }
    }
}
</script>

watch跟watchEffect

watchEffect

  • 当传入一个函数时,可以响应式的自动收集依赖,当依赖变更时重新运行该函数;
  • 使用是需要配置flush: post,否则依赖在监听时无法被立即更新
  • 也可以使用stop来立即停止对函数的监听
<template>
    <div ref="root">This is a root element</div>
</template>
<script>
import {ref, watchEffect} from 'vue'
export default {
    setup() {
        const root = ref(null)
        watchEffect(() => {
            console.log(`watchEffect监听:${root.value}`);
        }, {
            flush: 'post'
        })
        return {
            root
        }
    },
}
</script>

watch

watch API 与选项式 API this.$watch (以及相应的 watch 选项) 完全等效。watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用。默认情况下,它也是惰性的——即回调仅在侦听源发生变化时被调用。

watchEffect 相比,watch

  • 是一个返回任意值的getter函数
  • 是一个包装的对象,可以是ref对象、也可以reactive对象
  • 可以同时监听多个数据源
  • 监听是需要配置deep: true,否则回调函数无法被触发
<template>
    <h3>监听单个数据源1:{{state1.count}}</h3>
    <button @click="handleWatchSingle1">watch监听测试1</button>
    <h3>监听单个数据源2:{{state2}}</h3>
    <button @click="handleWatchSingle2">watch监听测试2</button>
    <h3>监听复杂对象数据源:{{state3.player}}</h3>
    <button @click="handleWatchSingle3">watch监听测试3</button>
</template>
<script>
import {ref, reactive, watch} from 'vue'

export default {
    setup() {
        const state1 = reactive({ count: 1 })
        const state2 = ref(0)
        const state3 = reactive({
            player: {
                name: 'James',
                achievement: ['4次NBA常规赛mvp', '03年选秀状元', '4次NBA总冠军']
            }
        })
        watch(() => state1.count, (newVal, oldVal) => {
            console.log('watch监听reactive中的newVal:', newVal);
            console.log('watch监听reactive中的oldVal:', oldVal);
        })
        watch(() => state2.value, (newVal, oldVal) => {
            console.log('watch监听ref中的newVal:', newVal);
            console.log('watch监听ref中的oldVal:', oldVal);
        })
        watch(() => state3.player, (newVal, oldVal) => {
            console.log('watch监听复杂对象中的newVal:', newVal);
            console.log('watch监听复杂对象中的oldVal:', oldVal);
        }, {
            deep: true,
            // immediate: true
        })
        // 同时监听多个值
        // watch([() => state1.count, state2.value], ([newVal1, newVal2], [oldVal1, oldVal2]) => {
        //     console.log('watch监听中的newVal:', newVal1, newVal2);
        //     console.log('watch监听oldVal:', oldVal1, oldVal2);
        // })
        function handleWatchSingle1() {
            state1.count++
        }
        function handleWatchSingle2() {
            state2.value++
        }
        function handleWatchSingle3() {
            state3.player = {
                name: 'Wade',
                achievement: ['3次NBA总冠军', '曾经的热火三巨头之一', '1次NBA总决赛mvp']
            }
        }
        return {
            state1,
            state2,
            state3,
            handleWatchSingle1,
            handleWatchSingle2,
            handleWatchSingle3
        }
    },
}
</script>

computed(计算属性)

  • 接受一个 getter 函数,并根据getter 的返回值返回一个不可变的响应式 ref 对象。
  • 接受一个具有 getset 函数的对象,用来创建可写的 ref 对象
<template>
    <div style="margin-top:30">
        <h3>computedNum值为:{{computedNum}}</h3>
        <h3>computedNum2值为:{{computedNum}}</h3>
        <button @click="handleComputed">computed计算测试</button>
    </div>
</template>

<script>
import { ref, computed } from 'vue'

export default {
    setup() {
        const state = ref(1)
        const computedNum = computed(() => {
            return state.value + 1
        })
        console.log('computed缓存后的值:', computedNum.value);
        // 只可读属性,不可写,会抛出警告 Write operation failed: computed value is readonly
        function handleComputed() {
            computedNum.value++
        }
        const computedNum2 = computed({
            get: () => state.value + 2,
            set: val => {
                count.value = val - 0
            }
        })
        return {
            computedNum,
            computedNum2,
            handleComputed
        }
    },
}
</script>

组件通信

组件通信这块跟vue2的区别不大,我们就拿常用的props跟emit来讲解一下。

props

  • 父级组件向子组件传递数据

emit

  • 子组件想父组件传递数据
  • 需要通过emits选项来定义组件可触发的事件

父组件

<template>
   <Children :msg1="msg1" :msg2="msg2" @childClick="handleClick" />
</template>
<script>
import {ref, reactive} from 'vue';
import Children from './children.vue'

export default {
    setup() {
        const msg1 = ref('给子组件传递的消息1')
        const msg2 = reactive({
            name: '给子组件传递的消息2'
        })
        return {
            msg1,
            msg2
        }
    },
    methods: {
        handleClick(val) {
            console.log('接收子组件emit过来的数据:', val);
        }
    },
    components: { Children }
}
</script>

子组件

<template>
    <div style="margin-top: 30px">props传递给子组件的消息:{{ msg1 }}</div>
    <button @click="$emit('childClick', 6666)" style="margin-top: 30px">向父组件emits事件</button>
</template>
<script>
export default {
    props: ['msg1', 'msg2'],
    emits: ['childClick'],
    setup(props) {
        console.log('子组件接收父级组件传递过来的消息:', props);
    },
}
</script>

插槽

vue2中的使用

子组件

<template>
    <slot name="title"></slot>
</template>

父组件

<template slot="title">
    <h2>周岭:《认知觉醒》</h2>
<template>

vue3中的使用

vue3插槽中提供了v-slot:name 写法,我们就拿作用域插槽来举例

子组件

我们定一个可循环的插槽content

<template>
    <!-- <slot name="title"></slot> -->
    <div v-for="(item, index ) in items" :key="index">
        <slot :item="item" name="content"></slot>
    </div>
</template>

<script setup>
import {ref} from 'vue';
const items = ref(['认知觉醒', '认知驱动']);
</script>

父组件

父组件中可以有两种方式来引入子组件中的插槽,其一是通过v-slot:content="scopend"的方式,其二是通过简写#content="{item}"的方式

<template>
    <SlotChild>
        <!-- <template v-slot:content="scoped">
            <div>{{ scoped.item }}</div>
        </template> -->

        <template #content="{item}">
            <div>{{ item }}</div>
        </template>
    </SlotChild> 
</template>

<script setup>
import SlotChild from './SlotChild.vue'
</script>

生命周期

vue3的声明周期如果是使用选项性Api的话,原来的生命周期钩子可以照常使用,那如果选用vue3组合式Api的话,生命周期需要通过import引入的方式在setup中调用。下图是vue3跟vu2声明周期的区别

<template>
    <div id="test">
        <h3>{{ counter }}</h3>
        <button @click="handleClick">声明周期测试</button>
    </div>
</template>

<script>
import {
    ref,
    onMounted,
    onBeforeMount,
    onBeforeUpdate,
    onUpdated,
    onBeforeUnmount,
    onUnmounted
} from 'vue'
export default {
    setup() {
        const counter = ref(0);
        console.log('....');
        function handleClick() {
            counter.value += 1;
        }
        onBeforeMount(() => {
            console.log("组件挂载之前");
        });
        onMounted(() => {
            console.log("DOM挂载完成");
        });
        onBeforeUpdate(() => {
            console.log("DOM更新之前", document.getElementById("test").innerhtml);
        });
        onUpdated(() => {
            console.log("DOM更新完成", document.getElementById("test").innerHTML);
        });
        onBeforeUnmount(() => {
            console.log("实例卸载之前");
        });
        onUnmounted(() => {
            console.log("实例卸载之后");
        });
        return {
            counter,
            handleClick
        }
    },
}
</script>

vue-router 4.0

vue-router 3.x跟vue-router 4.x比起来写法上的区别

vue-router 3.x

// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './routes'

Vue.use(Router)

const router = new Router({
  routes
})
export default router

// main.js
import Vue from 'vue'
import router from './router'
// ...

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

vue-router 4.x

// router/index.js
import { createRouter } from 'vue-router'
import routes from './routes'

const router = createRouter({
  history: createWEBHistory(), // history模式
  routes
})

// main.js
import { createApp } from 'vue'
import router from './router'

const app = createApp(App)
app.use(router)
app.mount('#app')
  • new Router()改成createRouter()
  • mode: 'history'改成 history: createWebHistory()

Composition API

useRouter、useRoute

通过useRouter进行路由跳转

<template>
  <div class="mg30">
    <el-button @click="handleJump" type="primary">关于我们</el-button>
  </div>
</template>

<script setup>
import { useRouter } from 'vue-router'

const router = useRouter()

const handleJump = (query) => {
  router.push({ 
    name: "about", 
    query: {
      id: 1
    }
  }) 
}
</script>

通过useRoute来获取传递过来的id

<template>
    <div>关于我们</div>
</template>

<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()
console.log('id>>>', route.query.id);
</script>

路由守卫

全局守卫

/router/index.js

详情页面meta中添加登录标识needLogin

let routes = [
    {
        path: '/detail',
        name: 'detail',
        component: () => import('@/views/detail.vue'),
        meta: {
            needLogin: true
        }
    }
]

main.js

添加守卫

import router from './router'

// 全局路由守卫
router.beforeEach((to, from) => {
    if (to.meta.needLogin) {
        return {
            name: 'login'
        }
    }
})

路由独享守卫

/router/index.js

let routes = [
    {
        path: '/cateGory/:id',
        name: 'category',
        component: () => import('@/views/category.vue'),
        beforeEnter: (to, from) => {
            // 如果不是正确的分类,跳转到NotFound的页面
            console.log('id>>>>', to.params.id);
            if (!["0", "1", "2"].includes(to.params.id)) { 
              return {
                name: "NotFound",
                // 这个是在地址栏保留输入的信息,否则地址栏会非常的丑
                params: { pathMatch: to.path.split("/").slice(1) },
                query: to.query,
                hash: to.hash,
              };
            }
        }
    }
]

组件内部守卫

<template>
    <div>关于我们</div>
</template>

<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'


// 页面内部的路由守卫
onBeforeRouteLeave((to, from) => {
    const answer = window.confirm('是否确认离开') 
    if (answer) { 
        console.log('不离开'); 
        return false 
    }
})

// 对于一个带有动态参数的路径 /category/:catId,在 /category/1 和 /category/2 之间跳转的时候, 会触发onBeforeRouteUpdate的路由钩子函数,在钩子函数中可以进行数据的更新。
onBeforeRouteUpdate((to, from) => {
     console.log('to>>>', to);
     console.log('from>>>', from);
    // if (to.params.id !== from.params.id) {
    //     userData.value = await fetchUser(to.params.id)
    // }
})
</script>

keep-alive 和 transition 必须用在 router-view 内部

// vue-router 3
<keep-alive> 
 <router-view /> 
</keep-alive> 
 
// vue-router 4 
<router-view v-slot="{component}"> 
 <keep-alive> 
  <component :is="component" /> 
 </keep-alive> 
</router-view> 

style新特性

跟vue2不同的是,vue3中提供了提供了很多不同的选择器方便我们在样式编写上更加的灵活多变。

深度选择器

类似于sass语法中的v::deep,不过vue3中的样式自带深度作用域

<style scoped>
.parent :deep(div) {
    margin-bottom: 10px;
}
</style>

<template>
  <div class="parent">
    <div class="set-up">:deep 深度作用域测试</div>
  </div>
</template>

全局选择器

不用像vue2一样写全局作用域时,需要单独开启一个style标签,同时去掉scoped属性;vue3提供了一种便捷的写法,只需要使用global属性传递你想全局修改的样式即可。

<template>
    <div>全局选择器测试</div>
    <p :class="$style.green">module样式测试</p>
</template>

<style scoped>
:global(div) {
    color: red;
}
</style>

<style module> 标签会被编译为 CSS Modules 并且将生成的 CSS 类作为 $style 对象的键暴露给组件。

<template>
    <p :class="$style.green">module样式测试</p>
</template>

<style module>
.green {
    color: green;
}
</style>

通过module自定义注入名称

<template>
    <p :class="classes.blue">useCSSModule样式测试</p>
</template>

<style module="classes">
.blue {
    color: blue;
}
</style>

与组合式 API 一同使用

<script>
import { h, useCssModule } from 'vue'
export default {
  setup() {
    const style = useCssModule()
    return () =>
      h(
        'div',
        {
          class: style.success
        },
        'Task complete!'
      )
  }
}
</script>

<style module>
.success {
  color: #090;
}
</style>

Typescript基础&项目中如何使用Typescript

对于TS,笔者认为小项目中也不必集成TS,反倒会提升项目的编译成本。那如果是大型项目的话,有必要尝试接入TS,一方面可以减少不必要的类型判断及文档注释,同时可以及早的发现错误,做静态类型检查时就可以及时的发现问题。另一方面,类、接口的使用更易于构建和维护组件;那么,对于初学者我们有必要对TS的一些基本用法做一下普及。

基本的数据类型


let isDone: boolean = false;
console.log('isDon', isDone);

let num: number = 1;
console.log('num', num);

let str: string = '认知觉醒';
console.log('str', str);

let arr: number[] = [1, 2, 3];
console.log('arr', arr);

// 泛型数组
let arr2: Array<number> = [1, 2, 3]
console.log('arr2', arr2);

let obj: Object = { id: 1 }
console.log('obj', obj);

let u: undefined = undefined
console.log('u', u);

let n: null = null;
console.log('n', n);

枚举

// 数字类型枚举与数字类型
enum CardSuit {
    Clubs,
    Diamonds,
    Hearts,
    Spades
}

console.log('CardSuit', CardSuit.Clubs); // 0
let col = CardSuit.Clubs;
col = 0 // 安全有效的
console.log('col', col); // 0

// 数字类型枚举与字符串类型
enum Tristate {
    False,
    True,
    Unkonw
}
console.log('字符串', Tristate[0]); // 'False'
console.log('number', Tristate['False']); // 0
console.log('字符串', Tristate[Tristate.False]); // 'False'

// 字符串枚举
enum LogLevel {
    info = 'info',
    warn = 'warn',
    error = 'error'
}
console.log('LogLevel', LogLevel.info); // 'info'

元祖


let x: [string, number, boolean];
x = ['hello', 10, true];
console.log('正确元祖', x); // ['hello', 10, true]
// y = [10, 'hello', false]
// console.log('错误的元祖', y);

任意值 Any


let notSure: any = 4;
notSure = 'maybe a string instead';
console.log('notSure', notSure); // 'maybe a string instead'
notSure = true;
console.log('notSure', notSure); // true

空值 void


const voidFunc = (): void => {
    console.log('这个函数没有返回任何值');
    // return msg; // 不能return
}
voidFunc()

interface


interface Point {
    x: number
    y: number
    z?: number
    readonly l: number
}

const point: Point = { x: 10, y: 20, z: 30, l: 40 }
console.log('point', point);

const point2: Point = { x: '10', y: 20, z: 30 } // Error x应该是Number类型

const point3: Point = { x: 10, y: 20, z: 30 } // Error l字段也是必传

const point4: Point = { x: 10, y: 20, z: 30, l: 40, m: 50 } // Error m字段没有定义

const point5: Point = { x: 10, y: 20, l: 40 } // 正常
point5.l = 20; // Error l字段是只读类型,不能修改

函数参数类型与返回值类型


function sum(a: number, b: number): number {
    return a + b;
}
console.log('sum', sum(2, 3)); // 5

// 配合interface使用
interface Point {
    x: number
    y: number
}

function sum2({x, y}: Point): number {
    return x + y;
}
console.log('sum2', sum2({x: 1, y: 2})); // 3

泛型



// 比如我们最初设计函数identity 入参为String
function identity(arg: String) {
    return arg;
}
console.log(identity('hello')); // hello

// 后来随着业务的迭代我们又需要支持 Number
function identity2(arg: String) {
    return arg;
}
console.log(identity(2)); // Argument of type 'number' is not assignable to parameter of type 'String'

// 那我们为什么不用any呢?使用any会导致丢失掉一些信息,我们无法确定要返回值到底是属于什么数据类型
const hello1: String = 'Hello vue3';
const hello2: Number = 666;
function say<T>(arg: T): T {
    return arg;
}
console.log('泛型1:', say(hello1)); // Hello vue3
console.log('泛型2:', say(hello2)); // 666

// 泛型约束
// 我们使用同样的例子,加了一个console,但是很不幸运,报错了,因为泛型无法保证每种类型都有.length 属性
const hello3: String = 'Hello vue3';
function say2<T>(arg: T): T {
    console.log(arg.length); // Property 'length' does not exist on type 'T'
    return arg;
}
console.log('泛型3:', say2(hello3)); // Hello vue3

interface Lengthwise {
    length: number
}

function say3<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}
console.log(say3(1)); // Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.
console.log(say3({ value: 'hello vue', length: 10 })); // '{ value: 'hello vue', length: 10 }'

交叉类型

interface foo {
    x: number
}

interface bar {
    b: string
}

type intersection = foo & bar

const result: intersection = {
    x: 10,
    b: 'hello'
}

console.log('result', result);

联合类型


type arg = string | number | boolean

const foo = (arg: arg): any => {
    console.log('arg', arg);
}
foo(1)
foo('1')
foo(true)

函数重载



// add函数,它可以接收string类型的参数进行拼接,也可以接收number类型的参数进行相加
function add <T, U>(arg1: T, arg2: U) {
  // 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 arg1 + arg2
  if (typeof arg1 === 'string' && typeof arg2 === 'string') {
    return arg1 + arg2
  } else if (typeof arg1 === 'number' && typeof arg2 === 'number') {
    return arg1 + arg2
  }
}
console.log('number类型相加', add(1, 2));
console.log('string类型拼接', add('1', '2'));

vue3项目中如何集成TS

  • 首先,你可以在初始化项目的时候就选择TS模板,直接将TS相关配置集成到项目中去。
  • 当然,你也可以手动去配置TS

安装TS

npm i typescript

项目根目录新建tsconfig.JSON文件,用于TS的编译基础文件

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src*.ts", "src*.d.ts", "src*.tsx", "src*.vue"]
}
  • 项目中使用

script标签中声明langg="ts",然后就可以愉快的使用TS的项目语法了,下边这段代码只是一些简单的示例。

<template>
   <div>
    <h2>标题:{{book.title}}</h2>
    <h2>作者:{{book.author}}</h2>
    <h2>出版日期:{{book.year}}</h2>
    <hr>
    <h3>{{allTitle}}</h3>
    <el-button @click="setTitle('我是传入的数据')" type="primary">设置数据</el-button>
  </div>
</template>

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

// 定义Book接口
interface Book {
    title: String
    author: String
    year?: Number,
    handleChangeName?(): void
}
      
export default defineComponent ({
    data() {
        let book: Book = {
            title: 'vue3 typescript',
            author: "vue Team",
            year: 2020,
        }
        return {
            book
        }
    },
    setup() {
        let year1 = ref<String | Number>('2022')
        console.log('year1', year1.value);
        
        // 第一种方式
        // const book1: Book = reactive({
        // name: year1.value,
        // desc: "vue3 进阶学习加油",
        // setNamechange(){
        //     this.name = "我是新设置的"
        // }
        // });
        // // 第二种方式
        // const book2 = reactive<Book>({
        // name: "vue3--typeScript",
        // desc: "学习ts加油",
        // year: 2020,
        // });
        // // 第三种方式
        // const book3 = reactive({
        //     name: "vue3--typeScript-第三种方式",
        //     desc: "ts类型第三种方式",
        //     year: 2022,
        // }) as Book;
    
        return {
            // ...toRefs(book1),
            // book2,
            // book3,
            // year1,
        };
    },
    computed: {
        // 返回值类型为String
        allTitle(): String {
            return `欢迎语 : ${this.book.title}`
        }
    },
    methods: {
        // 入参为String 返回空值
        setTitle(arg: String): void {
            this.book.title = arg;
            this.book.year = 2022
            this.book.author = '尤雨溪'
        }
    }
})
</script>

状态管理Pinia

由于本文章篇幅较大,会在之后的文章中单独来讲解。

到此这篇关于vue3基础知识剖析的文章就介绍到这了,更多相关vue3基础知识内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: vue3基础知识剖析

本文链接: https://www.lsjlt.com/news/171934.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • vue3基础知识剖析
    目录声明vue3.0有哪些新特性vue3.0的优缺点如何解锁vue3.0体验vue3.0的4中姿势核心的composition APIsetupsetup语法糖ref、reactiv...
    99+
    2022-11-13
    vue3基础知识 vue3基础
  • JavaScript基础知识点分析
    这篇“JavaScript基础知识点分析”除了程序员外大部分人都不太理解,今天小编为了让大家更加理解“JavaScript基础知识点分析”,给大家总结了以下内容,具有一定借鉴价值,内容详细步骤清晰,细节处理妥当,希望大家通过这篇文章有所收获...
    99+
    2023-06-06
  • Python基础知识点分析
    本篇内容介绍了“Python基础知识点分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Python简介Python的历史1989年圣诞节:...
    99+
    2023-06-02
  • 分析HTML基础知识DIV
    这篇文章主要介绍“分析HTML基础知识DIV”,在日常操作中,相信很多人在分析HTML基础知识DIV问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”分析HTML基础知识DIV”...
    99+
    2024-04-02
  • 分析HTML与CSS基础知识
    这篇文章主要介绍“分析HTML与CSS基础知识”,在日常操作中,相信很多人在分析HTML与CSS基础知识问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”分析HTML与CSS基础...
    99+
    2024-04-02
  • Python基础知识实例分析
    这篇文章主要介绍了Python基础知识实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Python基础知识实例分析文章都会有所收获,下面我们一起来看看吧。在Python 语言中,对象是通过引用传递的。多元...
    99+
    2023-06-17
  • PHP数组基础知识解析
    PHP数组基础知识解析 在PHP中,数组是一种非常重要且常用的数据类型,可以存储多个值并通过索引或键来访问这些值。本文将从基础开始,介绍PHP数组的使用方法和一些常见操作,同时会提供具...
    99+
    2024-03-13
    php 数组 基础 键值对
  • python3基础知识
    字符串截取:利用下标进行截取py_str = 'python'len(py_str)py_str[:3] py_str + '123''python123'py_str * 3'pythonpythonpython' Str将数...
    99+
    2023-01-31
    基础知识
  • python基础知识
    1.注释   1.1.单行注释:以#开头,#右边的有所东西当做说明.   1.2.多行注释:'''   我是多行注释   '''   2.变量   2.1.为了充分的利用内存空间以及更有效率的管理内存,变量是有不同类型的     2.1....
    99+
    2023-01-30
    基础知识 python
  • Python 基础知识
    只是打印出 hello world 肯定是不够的,是吗?你会希望做得比这还要多——你想要输入一些内容,操纵它,然后从中得到一些输出出来的内容。我们可以在 Python 中通过使用变量与常量来实现这一目标,在本章中我们还会学习其它的一些概...
    99+
    2023-01-31
    基础知识 Python
  • 基础知识—3.12
    1、二叉树: 结点:所有的叶子。 叶子结点:最后一层的叶子数。 性质1:二叉树第i层上的结点数目最多为 2{i-1} (i≥1)。性质2:深度为k的二叉树至多有2{k}-1个结点(k≥1)。性质3:包含n个结点的二叉树的高度至少为log2...
    99+
    2023-01-30
    基础知识
  • AngularJS基础知识的示例分析
    这篇文章主要介绍了AngularJS基础知识的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。指令AngularJS 指令是扩展的 H...
    99+
    2024-04-02
  • mysql基础知识-3
    一、mysql修改用户密码方法:    方法一:mysqladmin -u username -h host -p password 'new_password';    方法二:mysql>set password for 'use...
    99+
    2023-01-31
    基础知识 mysql
  • Linux基础知识3
     Linux 命令的语法格式COMMAND options arguments 命令可分为:命令、应用程序、脚本文件三类命令按类型分为:内部命令:即集成在系统内核中的命令外部命令:独立的可执行程序,程序名即为命令名区分内部命令或外部命令可使...
    99+
    2023-01-31
    基础知识 Linux
  • RabbitMQ的基础知识
    目录RabbitMQ1.对MQ的介绍2.RabbitMQ的六种模式 及工作原理3.hello world队列4.工作队列模式5.消息应答机制自动应答手动应答消息自动进行重新入队6.R...
    99+
    2024-04-02
  • Kubernetes(K8S)基础知识
    目录Kubernetes 是什么Kubernetes 集群的组成Kubernetes 结构组件Master 节点kube-apiserveretcdkube-schedulerkub...
    99+
    2024-04-02
  • 【MySQL】基础知识(二)
    MySQL基础知识(二) 文章目录 MySQL基础知识(二)01 表操作1.1 创建表1.2 查看所有表1.3 查看指定表的结构1.4 删除表练习 02 CURD2.1 新增2.1.1 ...
    99+
    2023-09-06
    mysql adb android
  • 一、PyQt基础知识
    一、基础知识 (一)简介 1. 什么是PyQt5 PyQt是基于Digia公司强大的图形程序框架Qt的Python接口,由一组Python模块构成,它是一个创建GUI应用程序的工具包,由Phil Th...
    99+
    2023-09-11
    pyqt qt python
  • python之基础知识
    1、变量: 2、字符串:用   “  ” 或 ' ' 标注的。 3、列表:[  ] 4、del 和 pop 的区别: 判断何时使用:当从列表中删除元素后不再使用,则del,若后续还使用则pop() 例: #del name =["lele...
    99+
    2023-01-30
    基础知识 python
  • Python基础知识(一)
      #Python中开始那个Hello World挺简单的。  #!user/bin/env python3  #这一行是shebang,用以指示用哪个解释器来执行,如果有的话,必须在程序第一行  print("Hello World!")...
    99+
    2023-01-31
    基础知识 Python
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作