vue3.x + typeScript 知识点

前言

不知不觉已经记录了这么多的知识点,更新一下吧。
可能比较杂乱,请谅解。

正文

  1. ref()reactive()函数都是定义响应式数据的函数,ref更倾向于定义简单类型和数组,reactive定义对象
  2. es6语法解构reactive所定义的响应式对象,会让其失去响应式。应用...toRefs方法
  3. 基本写法
<script lang="ts">
import {defineComponent, ref} from 'vue';

export default defineComponent({
  name: 'App',
  setup() {
    const girls = ref(['貂蝉', '昭君', '大乔', '小乔'])
    const selectedGirl = ref('')

    const selectGirl = (index: number): void => {
      selectedGirl.value = girls.value[index]
    }

    //返回才能在模板中使用
    return {
      girls,
      selectedGirl,
      selectGirl
    }
  }
});
</script>
  1. 改进上述代码
<script lang="ts">
import {reactive, toRefs} from 'vue';

interface DataProps {
  girls: string[],
  selectedGirl: string,
  selectGirl: (index: number) => void;
}

export default {
  name: 'App',
  setup() {
    const data: DataProps = reactive({
      girls: ['貂蝉', '昭君', '大乔', '小乔'],
      selectedGirl: '',
      selectGirl(index: number): void {
        data.selectedGirl = data.girls[index]
      },
      name: 'zed'
    })

    return {...toRefs(data)}
  }
};
</script>
  1. 接口中的数据,只要被检测数据全部拥有且类型正确,即可
  2. 生命周期函数
    • 3.x的生命周期函数需要引入,2.x原有的不需要
    • 3.x都在setup()中使用,2.x原有的不需要
    • 3.x和2.x的生命周期函数不要一起使用
    • onRenderTracked,onRenderTriggered跟踪发生变化的值,调试用
    onBeforeMount(() => {
      console.log('挂载前')
    })

    onMounted(() => {
      console.log('挂载完成')
    })

    onBeforeUpdate(() => {
      console.log('数据更新前')
    })

    onUpdated(() => {
      console.log('数据更新完成')
    })

    onBeforeUnmount(() => {
      console.log('卸载组件前')
    })

    onUnmounted(() => {
      console.log('卸载组件完成')
    })
  1. watch
//第一个参数数组,是要监视的值,发生变化则触发钩子,数组里是getter格式函数
watch([() => data.overText, () => data.selectedGirl], (newVal, oddVal) => {
      if (newVal[0] !== oddVal[0]) {
        document.title = newVal[0]
      }
    })
  1. toRefs()用于将被reactive()建造出来的响应对象变为普通对象,但对象里的属性都具有响应式。
  2. Suspense 异步组件
<template>
  <h2>{{ name }}</h2>
  <h2>{{ age }}</h2>
  <h2>{{ gender }}</h2>
</template>

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

export default {
  name: "AsyncUserInfo",
  async setup() {
    try {
      const res = await axios.get('http://localhost:3000')
      const data = reactive(res.data)
      return {...toRefs(data)}
    } catch (e) {
      console.log(e.message)
    }
  }
}
</script>

<style scoped>

</style>
<Suspense>
    <template #default>
      <async-user-info/>
    </template>
    <template #fallback>
      <h2>loading...</h2>
    </template>
  </Suspense>
  1. Teleport将组件挂载到某个DOM节点上,而不一定是#app
    • CSS 会独立,不受’#app’的影响。(毕竟没有挂载到#app
  2. 计算属性
import {defineComponent, reactive, computed, toRefs} from 'vue';

interface User {
  name: string,
  age: number,
  score: number,
  pet: {
    name: string,
    type: string
  }
}

export default defineComponent({
  name: 'App',
  setup() {
    const userinfo: User = reactive({
      name: 'zed',
      age: 18,
      score: 60,
      pet: {
        name: 'jeff',
        type: 'cat'
      }
    })

    const gt60 = computed(() => {
      return userinfo.score >= 60
    })

    const introduce = computed(() => {
      return `${userinfo.name},今年${userinfo.age}岁,我的宠物叫${userinfo.pet.name},是一只${userinfo.pet.type}`
    })

    return {...toRefs(userinfo), gt60, introduce}
  }
});
  1. readonly
    • 无法修改ac,尝试修改的话,vue会抛出警告
const article = reactive({
      title: '错把妻子当帽子',
      content: '神经病例'
    })

const ac = readonly(article)
  1. props
export default {
  props: {title: String},
  setup(props: any) {
    const titleP = ref(`这是一个标题:${props.title}`)
    return {titleP}
  }
  1. provide inject
    • 父级向后代传递数据
    • 注意!在后代组件中可以修改父级组件所传递的数据,且会响应式地影响到父级数据
    • 当使用响应式 provide / inject 值时,建议尽可能,在提供者内保持响应式 property 的任何更改。
    • 然而,有时我们需要在注入数据的组件内部更新 inject 的数据。在这种情况下,我们建议 provide 一个方法来负责改变响应式 property。此时,本质上改变的还是父组件的数据。
    • 最后,如果要确保通过 provide 传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly。
    • 父组件中
 setup() {
    const article = reactive({
      title: '错把妻子当帽子',
      content: '神经病例'
    })
    const updateFoo = ()=>{
      foo.value = '111'
    }
    let foo = ref('你好')

    provide('article', readonly(article))
    provide('foo', readonly(foo))
    provide('updateFoo',updateFoo)

    return {foo, article}
  }
- 子组件中
setup() {
    let foo = inject('foo')
    let article = inject('article')
    const updateFoo = inject('updateFoo')

    return {foo, article, updateFoo}
  }
  1. 实现接口的方法
    • reactive来说有三种
    • ref只能用泛型
    //1.泛型
    const book = reactive<Book>({
      title: 'title',
      author: 'author'
    })
    //2.断言
    const book = reactive({
      title: 'title',
      author: 'author'
    }) as Book
    //3. 类型声明
    const book:Book = reactive({
      title: 'title',
      author: 'author'
    })

    //ref 只能 泛型
    const title = ref<string>('这是一个标题')

  1. 动态路由
  • 参数
//路由配置
path: '/article/:aid'
//跳转配置
<li v-for="(item,index) in list" :key="index">
      <router-link :to="`/article/${index}`">{{ item }}</router-link>
</li>
//如何获取
<h2>我是{{$route.params.aid}}文章页面</h2>
  • get传值
//路由配置
path: '/article'
//跳转配置
<router-link :to="`/article?aid=${index}`">{{ item }}</router-link>
//如何获取
<h2>我是{{$route.query.aid}}文章页面</h2>
  • 函数传值
    • 当你点击 时,这个方法会在内部调用,所以说,点击 等同于调用 router.push(…)。
<button @click="$router.push('/')">home</button>
<!-- 传值 这种方式会把键值对拼接到url后面,地址栏中会看到 -->
<button @click="$router.push({path:'/article',query:{aid:3}})">home</button>
<!-- 命名的路由,不会把键值对拼接到url上,params属性不能与path同时使用,否则params会失效 -->
<button @click="$router.push({name:'home',params:{uid:3}})">home</button>
<!-- router-link配置动态路由的另一种方式 -->
<li v-for="(item,index) in list" :key="index">
      <router-link :to="{name:'article',params:{aid:index}}">{{ item }}</router-link>
</li>
  1. 嵌套路由
    • children中的path,不需要加/
    • redirect,写成redirect: /user/userlist
  2. vuex在组合式API,即setup()中的使用
    • 不能通过this.$store来获取,要先引入useStore,然后创建实例,通过实例来获取其中的方法和属性
    • 获取的属性要使用计算属性定义在setup()中,才能获得响应式
    • 虽然
import { useStore } from 'vuex'

setup(){
    const store = useStore()
}
  1. vuex在ts中的写法
import {createStore} from "vuex";

const store = createStore({
    state: {
        authName: 'zed',
        bookList: ['错把妻子当帽子', '三体', 'js高级程序设计第三版', '撒哈拉的故事']
    },
    mutations: {
        changeName(state, name) {
            state.authName = name
        }
    }
})

export default store
  1. 计算属性的值是只读的
//尝试改变返回简单值得计算属性的值,vue会抛出警告
//Write operation failed: computed value is readonly
  1. ref
    • 在给name赋值时,如果不加.value,那么新添加的bookname都会绑定同一个name
let name = ref('')
books.value.unshift({id: id++, name: name.value, price: 127})
  1. 如果在async setup中使用生命周期函数,要放在第一个await之前
  2. setup(props, context),第二个参数中的emit即为vue2中的this.$emit,可用结构的语法写,即setup(props, { emit })
  3. sticky 定位
    sticky 英文字面意思是粘,粘贴,所以可以把它称之为粘性定位。position: sticky; 基于用户的滚动位置来定位。粘性定位的元素是依赖于用户的滚动,在 position:relative 与 position:fixed 定位之间切换。它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置。
  4. better-scroll 插件
<div class="wrapper">
<!-- 整体盒子,需要设置`overflow: hidden`以及宽高 -->
    <div class="content">
        <!-- 这里放置需要滚动的部分 -->
    </div>
    <!-- 在wrapper内部,content外部中的DOM,会被忽略 -->
</div>
  • DOM元素高度发生变化,就要调用实例的refresh方法
  1. vant的使用
    • $ npm i vant@next
    • 如果要按需引入,执行$ npm i babel-plugin-import -D
    • main.ts中引入import 'vant/lib/index.css'
    • 在局部组件中引入import {Swipe, SwipeItem} from "vant";,并在这个组件中注册子组件components: {[Swipe.name]: Swipe, [SwipeItem.name]: SwipeItem}
  2. 想要全局引入vant,可以在main.ts中引入并配置
    • vant配置图片懒加载,则要配置Lazyload,且将项目中需要懒加载的图片src改为v-lazy
import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'vant/lib/index.css'
import {Lazyload, SwipeItem, Swipe} from 'vant'

createApp(App)
    .use(Lazyload, {
        loading: require('./assets/img/book.svg')
    })
    .use(Swipe)
    .use(SwipeItem)
    .use(store).use(router)
    .mount('#app')

  1. vant徽标的使用
    • 使用van-badge标签包裹需要徽标的图标,指定内容长度和最大长度
<van-badge :content="20" max="9">
        <i class="iconfont icon-gouwuche2"></i>
</van-badge>
  1. v-bind绑定动态参数
    • 动态参数的缩写 (2.6.0+)
    • <a :[myHref]="myLink"></a>
    • myHref是在data中的动态属性名
  2. @click='fn(arg1,$event)'
    • arg1是自定义参数
    • $event是鼠标事件
  3. @click='fn1(),fn2(),fn3()'
    • 一个元素可以一次绑定多个触发函数
  4. 可以使用计算属性监听数据变化
  5. 也可以用watch监听数据变化,但是比较耗费性能
  6. 在 Vue3.x 中,组件现在支持有多个根节点
  7. 组件传值 this props $ref $parents 单向数据流 修改
    7.1 子访问父
    • props
      0. props:[key1,key2...]只能传值,无验证功能,可以改为props:{}
      1. 传递的数据如果不是静态字符串的话,那么属性名要加上v-bind
      2. 如果传输this,则是传输的是父组件的实例,可以访问到所有属性和方法
      3. 单向数据流,子组件无法修改父组件传来的值,父组件的值发生更新,那么子组件中也会更新
      4. 注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。
      5. 注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的 property (如 data、computed 等) 在 default 或 validator 函数中是不可用的。
    • $parents
      1. 获取到的是父组件的实例,可以访问属性和方法
      2. 可以改变父组件的属性和函数
        7.2 父访问子
    • $refs
      1. 获取到的是子组件的实例,可以访问属性和方法
      2. 可以改变子组件的属性和函数
    • $emit 自定义事件传递
      1. 无法改变子组件的数据
      2. 提交的时候,可以对数据进行验证 emits,如果违反验证规则会抛出警告
      3. 官方推荐使用连词符-来命名事件,即send-msg
        7.3 兄弟组件
    • 中介父组件
    • 第三方库mitt
  8. 全局属性
// 之前(Vue 2.x)
Vue.prototype.$http = () => {}

// 之后(Vue 3.x)
const app = Vue.createApp({})
app.config.globalProperties.$http = () => {}
  1. vuex
// @/stores/index.ts中的写法
import Vue from "vue";
import Vuex from "vuex"
import ActionHelper from "@/stores/ActionHelper";

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        globalProperty: '全局属性',
        ah: new ActionHelper()
    },
    mutations: {
        logProperty(state) {
            console.log(state.globalProperty)
        }
    }
})

// main.js 中的写法
import Vue from 'vue'
import App from './App.vue'
import store from './stores'

Vue.config.productionTip = false

new Vue({
    render: h => h(App),
    store
}).$mount('#app')

//使用方法
fn() {
      alert(this.$store.state.globalProperty)
      this.$store.commit('logProperty') 
    }

结语

如果对你有帮助的话,请点一个赞吧

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值