公告栏

此网站主题为本人手写主题, 主题待开源···

音乐盒

站点信息

文章总数目: 308
已运行时间: 1187
目录
  1. 数据
    1. 普通数据
    2. 响应数据
      1. ref
      2. reactive
    3. Vue2中的data
      1. 如何在setup中使用data中的数据库?
  2. 计算属性+方法+侦听器
    1. watch(侦听器)+computed(计算属性)+watchEffect
    2. Vue2中侦听器(watch)注意事项
      1. 使用deep属性
      2. 用字符串来表示对象的属性调用
      3. 使用计算属性(computed)
  3. 生命周期
  4. 具体使用
    1. router和route区别及使用
    2. Vue3中使用Async Await
    3. emit使用
    4. slot使用
    5. ref获取元素节点
    6. [取]函数式编程模式[弃]Mixin逻辑
    7. vue3中不要命名冲突
    8. vue3全局路由配置
    9. js/ts文件使用相应vue中函数
    10. 全局变量的使用
    11. v-if/else branches must use unique keys.vue(29)
    12. 具名插槽
    13. 注释导致页面不能渲染
    14. 样式只在当前页面有效
    15. vue2获取dom节点自定义属性值
    16. 根据dom属性来动态改变css
  5. 参考
尼采般地抒情

尼采般地抒情

尼采般地抒情

公告栏

此网站主题为本人手写主题, 主题待开源···

站点信息

文章总数目: 308
已运行时间: 1187

前言:使用Vue3(Vue.js - 渐进式 JavaScript 框架 | Vue.js)的 组合式API 编程风格来进行基础转换。


基础变动:

  • setup语法糖 Vue3.2之后才能放到script里面
  • data methods 都不再需要,也不再需要return出变量或是函数
  • 路由相关知识,只注意useRoute() useRouter()其余的,和之前自己写的lyrics前端路由就够用了
  • Vue3 异步编程
  • provide 和 inject
  • ······

语法转换过程中,主要分几个大块:

  • 语法:框架自行的一些语法迁移(官网里面的基础
  • 组件相关:尤其是组件之间的各类通信方式,以及封装组件的传参等,单独一篇文章总结。
  • 编程风格/封装相关
  • ······

数据

普通数据

<script setup lang="ts">
interface SpecialFunDataItem {
  title: string
  description: string
}
const apply_data: SpecialFunDataItem[] = [
  {
    title: '知识库/项目文档/产品手册',
    description: '适合',
  },
  {
    title: '帮助中心/FAQ/在线问答',
    description: '适合。',
  },
]
  </script>

响应数据

ref

<template>
  <a-modal
    v-model:visible="visible"、
    ···
    >
</template>
<script setup lang="ts">
import {ref} from 'vue'
const visible = ref<boolean>(false)
</script>

reactive

reactive这个更多使用在对象和数组类型的响应式定义数据,因为在vue2中,对于数组和对象是不能够完美响应式的,需要watch来监听实现,而在vue3中,以此作为优化来定义响应式数据。

但是直接使用ref也可以定义响应式数组或对象数据

  • reactive定义的数组不能实时渲染,用ref就完事了

Vue3异步请求获取数据在渲染时不显示的问题_s-010101的博客-CSDN博客_vue异步请求数据没渲染

并不是生命周期的问题,而是数据定义的问题

除了上述两种方式解决办法,还可以使用ts语法,接口,参照antdv中的表单相关实例代码

  • reactive不能渲染,更新名称子组件不能渲染
  • FIXME: 重命名组件中,输入框值变化不能响应式

同时对数据定义用ref不用reactive

Vue2中的data

如何在setup中使用data中的数据库?

按照以前vue2,直接使用this可以访问到data中定义的数据,但在vue3不行,因为setup()函数的执行要比created,oncrated函数都要早。

具体使用以下小技巧可以访问到:

<div v-on:click="fun(testdata)"></div>

setup(){
    const  fun=(i)=>{
      alert(i)
    }
},
data(){
    return{
       testdata:1,
    }    
}

也可以使用getCurrentInstance方法获取data内的数据(未验证)

<script lang="ts">
import { getCurrentInstance } from "vue";
export default {
  data() {
    return {
      b: "data数据",
    };
  },
  setup() {
    const datab = getCurrentInstance();
    async function getdata(){
        let dataa=datab.data.b;
        console.log(dataa)
    }
  },
};
</script>


计算属性+方法+侦听器

计算属性(computed)和方法(methods)的区别

  • 计算属性是基于他们的依赖来进行缓存的

“他们的依赖”指的是data数据域中的data数据,如果其变动,计算属性值才会变

  • 方法不存在缓存

计算属性(computed)和侦听器(watch)的使用

  • 侦听器更用于异步或是开销较大的操作

watch(侦听器)+computed(计算属性)+watchEffect

  • watchEffect:只要在该函数引用声明式变量,那么就会执行该函数

为了根据响应式状态自动应用和重新应用副作用,我们可以使用 watchEffect 函数。它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

  • watch:vue2中监听新值和旧值的一样使用(ref reactive 各有不同)
  • computed
  • 动态监听数组,返回的新值打印出来都是数组元素逗号隔开,因为监听的是内部每一个数组元素
<template>
  <button type="button" @click="count++">[watch watchEffect]ref 定义的 count is: {{ count }}</button><hr/>
  <button type="button" @click="numbers[0]++">[watch watchEffect]reactive 定义的 numbers is: {{ numbers }}</button><hr/>
  <button type="button" >[computed]ref 定义的 person_ref is: {{ person_ref }}</button><hr/>
  <button type="button" >[computed]reactive 定义的 person_reactive is: {{ person_reactive }}</button><hr/>
  <span>动态参数绑定:</span><a :href="getHrefValue()">{{getHrefValue()}}</a><hr/>

</template>

<script setup lang="ts">
import { ref, watchEffect, watch, reactive, computed, Ref } from 'vue'

const count = ref(0)
const numbers = reactive([1, 2, 3, 4])
let person_ref = ref('wuzutao')
let person_reactive = reactive({firstName:'wu', lastName:'zutao', fullName: 'wu-zutao'})

let getHrefValue = () => {
    return 'www.wztlink1013.com'
}

// [watchEffect ref reactive]
watchEffect(()=>{
  const x1 = count.value
  const x2 = numbers[0]
  console.log('因为watchEffect里面调用了count/numbers[0] 所以watchEffect所指定的回调执行了', x1, x2)
})
// [watch ref]
watch(count, (count, prevCount) => {
    console.log('新值', count)
    console.log('旧值', prevCount)
})
// [watch reactive]
watch(
  () => [...numbers],
  (numbers, prevNumbers) => {
    console.log('numbers新值',numbers)
    console.log('numbers旧值',prevNumbers)
  }
)
// [computed ref]
// const computed_ref = computed(() => { // 简单式
//     person_ref.value = person_ref.value + '+'
// })
const computed_ref = computed<any>({ // 复合式
  get: () => {
    console.log('[ref]使用(get)该变量,就会调用')
  },
  set: (val) => {
    console.log('[ref]改变(set)该变量,就会调用')
    person_ref.value = val + '-内部处理值-原始值' + person_ref.value
  }
})
// console.log(computed_ref.value) // 会打印undefined因为上面的get没有传参
computed_ref.value = '修改的目的值'

// [computed reactive]
// person['firstName'] = computed(()=>{
//     return person.firstName + '-' + person.lastName
//     }) 
 const computed_reactive= computed<any>({ // 完整写法
    get(){
        // return person_reactive.firstName + '-' + person_reactive.lastName
        console.log('[reactive]使用(get)该变量,就会调用')
    },
    set(value){
        console.log('[reactive]改变(set)该变量,就会调用')
        const nameArr = value.split('-')
        person_reactive.fullName = value
        person_reactive.firstName = nameArr[0]
        person_reactive.lastName = nameArr[1]
    }
})
computed_reactive.value = 'wu+-zutao+'
</script>



<style scoped>
a {
  color: #42b983;
}

label {
  margin: 0 0.5em;
  font-weight: bold;
}

code {
  background-color: #eee;
  padding: 2px 4px;
  border-radius: 4px;
  color: #304455;
}
</style>
  • vue3的监听器报重载错误

Vue2中侦听器(watch)注意事项

实际开发过程中:

  • 非的确必要,尽量不要使用watch监听,实际过程中,会造成许多问题,比如渲染顺序等,会给后续添加功能带来难以维护的问题
  • 当监听的数据不是一个简单的基本类型,比如一个对象,一个数组,此时应该使用深度监听:deep:true;当想让监听器一启动就触发一次watch,应该使用: immediate: true。

直接watch监听对象内的是检测不到变化的,因为对象的指向并没有发生改变。Vue中的watch监听对象内属性的变动方案

使用deep属性

new Vue({
  data: {
    count: 10,
    blog:{
        title:'my-blog',
        categories:[]
    }
  },
  watch: {
    blog:{
        handler(newVal,oldVal){
            console.log(`new: ${newVal}, old: ${oldVal}`);
        },
    deep:true
    }
  }
})


里面的deep设为了true,这样的话,如果修改了这个blog中的任何一个属性,都会执行handler这个方法。不过这样会造成更多的性能开销,尤其是对象里面属性过多,结构嵌套过深的时候。而且有时候我们就只想关心这个对象中的某个特定属性,这个时候可以这样

用字符串来表示对象的属性调用

new Vue({
  data: {
    count: 10,
    blog:{
        title:'my-blog',
        categories:[]
    }
  },
  watch: {
    'blog.categories'(newVal, oldVal) {
        console.log(`new:${newVal}, old:${oldVal}`);
    }, 
  }
})

使用计算属性(computed)

new Vue({
  data: {
    count: 10,
    blog:{
        title:'my-blog',
        categories:[]
    }
  },
  computed: {
    categories() {
      return this.blog.categories;
    }
  },
  watch: {
    categories(newVal, oldVal) {
      console.log(`new:${newVal}, old:${oldVal}`);
    }, 
  },
})

参考:https://segmentfault.com/a/1190000018080301

生命周期

  • 生命周期需要注意,没有created阶段了,直接在setup里面了,也就是setup阶段是没有挂载真实DOM的,如果需要操作真实dom需要在onMounetd里面进行相应逻辑
onMounted(() => {
  if ((document.getElementById('test') as HTMLElement) === null) {
    console.log('--------------');
  } else {
    console.log('+++++++++++++++++++++');
  }
});
  • bug:刚进入页面,下面的地方不会自动摊开宽度,获取dom的宽度失败

代码放到onMounted中即可

vue2当中:

  1. beforeCreate:在实例初始化之后,数据观测和事件配置之前被调用
  2. created:在实例创建完成后被立即调用
  3. beforeMount:在挂载开始之前被调用
  4. mounted:el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子
  5. beforeUpdate:数据更新时调用,发生在虚拟DOM打补丁之前
  6. updated:由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子
  7. beforeDestroy:实例销毁之前调用
  8. destroyed:实例销毁后调用

<script>
  setup() {
    console.log('----setup第一个执行----')
    // vue3.x生命周期写在setup中
    onBeforeMount(() => {
      console.log('------vue3中onBeforeMount-----')
    })
    onMounted(() => {
      console.log('------vue3中onMounted-----')
    })
    onRenderTriggered((event) => {
      console.log('------vue3中onRenderTriggered-----', event)
    })
  },
  // vue2当中的
  beforeCreate() {
    console.log('----vue2中beforeCreate第二个执行----')
  },
  // vue2当中的
  created() {
    console.log('----vue2中created第三个执行----')
  },
</script>

执行结果如下:

具体使用

router和route区别及使用

vue3中的useRoute()和useRouter(); - 掘金

Vue3中使用Async Await

const handleLoginOut = async () => {
  emit('wsClosed');
  const { ret } = await logout();
  if (ret > -1) {
    localStorage.clear();
    onRedirect();
  }
};

emit使用

slot使用

vue2:

<template>
  <template slot="content">
    ···
  </template>
</template>

vue3:

<template>
  <slot name="content">
    ···
  </slot>
</template>

ref获取元素节点

[取]函数式编程模式[弃]Mixin逻辑

  • cooperation的Mixin代码较难抽离出来

使用到较多的cooperation文件代码,Mixin逻辑,不再像Home组件中的上传逻辑一样直接放到一块,改用引用函数的方式,因为变量不多。

ylCooperationSdkInstance变量在组件中使用较少,但是如果直接引用ts文件中的变量,是否会存在不再响应的问题。使用vue3推荐的组合式函数编程方式:

https://cn.vuejs.org/guide/reusability/composables.html

  • 上面的mixin文件代码全部放在ts文件中,然后在vue中导入ts文件,其仍然保留生命周期
  • 单独ts文件是用不了全局变量

直接导入router文件,使用根源API

https://cn.vuejs.org/guide/reusability/composables.html#vs-mixins

  • 将上传逻辑js代码转为ts代码,然后再全量导入Home/index.vue中
  • data数据迁移
    • 里面应该只有uploadedNum变量再vue组件中使用到了
    • iconType变量两者都有

  • uploadHandler.ts上传逻辑代码进行ts转换。并且将代码放到组件中

在Home组件中,混合代码较多,其中,上传逻辑使用的是vue2.x的Minix混入方式,但是在vue3不再推荐该模式写代码,所以单独将上传逻辑js文件单独整理其逻辑,文件逻辑中,上传js代码和Home.vue组件两者相互又使用一些变量···

  • 上传js代码中有6处使用vue中的变量
  • vue中有2处使用js代码中变量

尝试方法1:因为两者多出混入变量使用,尝试将上传的ts代码全部放到Home组件中,虽然代码变长了,但是逻辑性提高了,先做出如下备份

vue3中不要命名冲突

会导致取值和预期取值不一样

pagination对象类型,在首页的分页逻辑有误


vue3全局路由配置

  • vue3路由全局匹配

vue3配置路由报错Catch all routes (“*“) must now be defined using a param with a custom regexp._Boale_H的博客-CSDN博客

js/ts文件使用相应vue中函数


全局变量的使用

vue3注册全局变量失去响应性

  • 点击登录按钮,相应一个loading的状态,这个在之前项目中是利用全局注册的一个变量,vue3的全局注册变量方法
  • 接口 - loading 的全局变量迁移

不能使用v3全局变量api getCurrentInstance 不能响应式,同时打包情况下

直接导入ts文件,在ts文件中做变量导出,

v-if/else branches must use unique keys.vue(29)

<template v-for="(item, index) in fileList">
  <a-menu-divider v-if="item.isDivider" :key="index" />
  <a-menu-item
    v-else
    :key="item.value"
    class="create-button-menu-item"
    @click="handleMenuClick(item.value)"
  >

将第五行代码中的index换成item.value,一是因为index在这里并没有传值的实际作用,而是解决key值相同问题

具名插槽

  • vue3插槽使用方式和vue2不一样,不能使用template,而是slot标签,name属性
  • 具名插槽在vue2和vue3两者使用有差别

注释导致页面不能渲染

上述箭头所标注的地方不要有注释,有注释会渲染不出来

样式只在当前页面有效

组件中style标签后面加上scoped就可以

<style lang="less" scoped></style>

vue2获取dom节点自定义属性值

vue如何获取自定义元素属性参数值_lotSeed_5的博客-CSDN博客_vue获取元素的属性值

根据dom属性来动态改变css

当给dom添加自定义属性,vue2和vue3实际渲染出来的不一样(如果是标签自身属性,vue3和vue2是一样的)

  • vue3
<div :selected="true">selected</div>
<div :selected="false">UnSlected</div>

  • vue2
<div :selected="true">selected</div>
<div :selected="false">UnSlected</div>

  • 根据以上不同,在css选择器使用有区别
  • vue3
//  vue3
div[selected=true] {
  color: red;
}
  • vue2
// vue2
div[selected] {
    color: red;
}

参考

评论区

Twikoo giscus