vue3遇到问题整理(不定期更新)

1.is="vue:script"

<div is="vue:script" 
	src="https://p.bokecc.com/player?newversion=true" 
	type="text/javascript" />

2.Volar vscode中插件的安装使用
3.reatvie,ref,unref,toRef/toRefs/isRef

reatvie

对应用类型数据进行包裹,使其称为响应式的数据,
vue不建议使用原对象(应用类型数据),
而直接使用包裹后的数据,因为包裹后就称为响应式数据。
如果强行拆开,使用原对象,则丧失了响应式。
reactive事项了原对象的拷贝,但他是深拷贝

const proxyObj=reactive({
      a:1,
      b:2,
      c:[
        {d:3,e:4},{f:3,g:5}
      ]
})
------------------------------
reactive的对象可以直接修改对象
//使用reactive包裹的对象会自动展开,state.myref等效于state.value.myref
console.log(state.myref)
//也可以直接修改数据,因为实际是自动展开了
state.myref=200
console.log(state.myref)
ref

包裹基本数据类型,返回响应式的ref对象
修改的话需要使用数据.value来使用
如果包裹一个应用类型,但实际返回的是reactive类型,并支持deep拷贝
return出去的被ref包裹的数据,会合并到render函数(h函数)里去。
并自动的将里面的value展开,如{{count}},而不用{{count.value}}
如果一个ref包裹了一个已经ref包裹的数据,新的ref会覆盖老的ref的值

setup(props,context){
    const myref=ref(100)
    const proxyObj=ref({
      a:1,
      b:2,
    })
    console.log(myref.value)
    console.log(proxyObj.value.a)
    const state=reactive({ myref })
    //使用reactive包裹的对象会自动展开,state.myref等效state.value.myref
    console.log(state.myref)
    //也可以直接修改数据
    state.myref=200
    console.log(state.myref)
    return {
      myref,
      state
    }
  },
unref

ref是深度响应的。深度以为这嵌套的对象,
深度响应表示嵌套的对象按照路径找下去是可以修改的

unref如果参数数据是ref包裹,就返回inner value,
如果不是ref包裹的数据,就返回数据本身
isRef函数判断(isRef判断是否为ref)
setup(props,context){
    const myobj={
      name:'zhangsan',
      age:22,
      address:'heibei'
    }

    const obj1=isRef(myobj) ? myobj.name : myobj
    console.log(obj1)

    const obj2=ref(myobj)
    const obj3=isRef(obj2) ? myobj.name : myobj
    console.log(obj3)
    //unref实际就等于上面的obj3
    const obj4=unref(obj2)
    console.log(obj4)
    const obj5=unref(myobj)
    console.log(obj5)
    return {
      myobj
    }
},
toRef/toRefs/isRef

1、toRef:建立reactive和ref的一种转换
可以把对象中的某个属性单独拿出来转成ref
const state=reactive({
      name:'Alice',
      age:23
})
//指定转换的属性,这里将state的reactive包装对象的name属性传给myref
const myref=toRef(state,'name')
//修改转换后的值
myref.value='prime'
console.log('Alice~name',state.name)
//修改state.name和修改myref.value都会影响到对方
state.name='wanger'
console.log('myref.value:',myref.value)
return {
  myref,
}
2、toRefs:建立reactive包装对象和ref的一种转换

将一个reactive包装好的对象,整个转换成一个ref包装成的对象
这样对象的所有属性都转换过去,而不是像toRef那样值转换其中的一个属性,
因此,只需要一个转换对象形参就可以

const state=reactive({
      name:'zhangsan',
      age:23
})

//指定转换的属性,这里将state的reactive包装对象的name属性传给myref
//这里转成了一个普通对象
const myrefs=toRefs(state)
console.log(myrefs)
console.log({
  ...myrefs
})
console.log('11111',myrefs.name.value)//zhangsan
console.log('11111',myrefs.age.value)//23
//修改转换后的值
myrefs.name.value='lisi'
myrefs.age.value=33
//修改转换后的值会影响到原则,因为实际本质上还是引用的
console.log(state.name)//lisi
console.log(state.age)//33
//修改state.name和修改myref.value都会影响到对方
state.name='wanger'
state.age=44
console.log('22222',myrefs.name.value)
console.log('22222',myrefs.age.value)
return {
  //直接展开转化后的myrefs,这样在template里面可以直接拿到展开后的name和age
  ...myrefs,
  state
}
最佳使用方式
通过上面的演示可以得出以下几点结论:

用 reactive 做对象的响应式,用 ref 做值类型的响应式。
setup 中返回 toRefs(state) ,或者 toRef(state, 'xxx') 。
为了防止误会产生, ref 的变量命名尽量都用 xxxRef ,这样在使用的时候会更清楚明了。
合成函数返回响应式对象时,使用 toRefs
(1)为什么需要用ref
值类型(即基本数据类型)无处不在,如果不用 ref 而直接返回值类型,会丢失响应式。
比如在 setup 、 computed 、合成函数等各种场景中,都有可能返回值类型。
Vue 如果不定义 ref ,用户将自己制造 ref ,这样反而会更加混乱。
(2)为何ref需要.value属性
通过上面的分析我们知道, ref 需要通过 .value 来修改值。这看起来是一个很麻烦的操作,总是频繁的 .value 感觉特别琐碎。那为什么一定要 .value 呢?我们来揭开它的面纱。

ref 是一个对象,这个对象不丢失响应式,且这个对象用 value 来存储值。
因此,通过 .value 属性的 get 和 set 来实现响应式。
只有当用于 模板 和 reactive 时,不需要 .value 来实现响应式,而其他情况则都需要。
(3)为什么需要toRef和toRefs
与 ref 不一样的是, toRef 和 toRefs 这两个兄弟,它们不创造响应式,而是延续响应式。创造响应式一般由 ref 或者 reactive 来解决,而 toRef 和 toRefs 则是把对象的数据进行分解和扩散,其这个对象针对的是响应式对象而非普通对象。总结起来有以下三点:

初衷: 在不丢失响应式的情况下,把对象数据进行 分解或扩散。
前提: 针对的是响应式对象( reactrive 封装的)而非普通对象。
注意: 不创造响应式,而是延续响应式。

4.Composition API

在逻辑组织和逻辑复用方面,Composition API是优于Options API
因为Composition API几乎是函数,会有更好的类型推断。
Composition API对 tree-shaking 友好,代码也更容易压缩
Composition API中见不到this的使用,减少了this指向不明的情况
如果是小型组件,可以继续使用Options API,也是十分友好的

5.Async Components 异步组件
6.vue3插槽
7.vue v-model绑定多个属性
8.TypeScript 声明复杂变量时 PropType

import {  PropType } from 'vue';
const props = defineProps({
  videoId: {
    type: String as PropType<string>,
    required: true,
  },
});
 interface otherBread {
    title: string;
    path: string;
  }

  export default {
    props: {
      otherBreadcrumb: {
        type: Array as PropType<otherBread[]>,
        default: () => [],
      },
    },
handler: {
  type: Function as PropType<Fn>,
  default: () => ({}),
},

8.ts中InstanceType使用

<template>
  <div class="login-panel">
    <h1 class="title">后台管理系统</h1>
    <el-tabs type="border-card" stretch v-model="currentTab">
      <el-tab-pane name="account">
        <template #label>
          <span><i class="el-icon-user-solid"></i> 账号登录</span>
        </template>
        <login-account ref="accountRef" />
      </el-tab-pane>
      <el-tab-pane name="phone">
        <template #label>
          <span><i class="el-icon-mobile-phone"></i> 手机登录</span>
        </template>
        <login-phone ref="phoneRef" />
      </el-tab-pane>
    </el-tabs>

    <div class="account-control">
      <el-checkbox v-model="isKeepPassword">记住密码</el-checkbox>
      <el-link type="primary">忘记密码</el-link>
    </div>

    <el-button type="primary" class="login-btn" @click="handleLoginClick"
      >立即登录</el-button
    >
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'
import LoginAccount from './login-account.vue'
import LoginPhone from './login-phone.vue'

export default defineComponent({
  components: {
    LoginAccount,
    LoginPhone
  },
  setup() {
    // 1.定义属性
    const isKeepPassword = ref(true)
    const accountRef = ref<InstanceType<typeof LoginAccount>>()
    const phoneRef = ref<InstanceType<typeof LoginPhone>>()
    const currentTab = ref('account')

    // 2.定义方法
    const handleLoginClick = () => {
      if (currentTab.value === 'account') {
        accountRef.value?.loginAction(isKeepPassword.value)
      } else {
        console.log('phoneRef调用loginAction')
      }
    }

    return {
      isKeepPassword,
      accountRef,
      phoneRef,
      currentTab,
      handleLoginClick
    }
  }
})
</script>

<style scoped lang="less">
.login-panel {
  margin-bottom: 150px;
  width: 320px;

  .title {
    text-align: center;
  }

  .account-control {
    margin-top: 10px;
    display: flex;
    justify-content: space-between;
  }

  .login-btn {
    width: 100%;
    margin-top: 10px;
  }
}
</style>

9.上传,下载(插件element-plus) 上传
<el-form-item label="测评图片" prop="img">
  <el-upload
	    ref="upload"
	    action="#"
	    class="upload-test"
	    :class="{ hide: hideUpload }"
	    :file-list="imageList"
	    :http-request="uploadFile"
	    :limit="1"
	    list-type="picture-card" // 点击图片放大
      const handlePictureCardPreview = (file) => {
        testNameImageUrl.value = file.url
        testNameImageVisible.value = true
      }
      // 上传文件列表删除
      const handleRemove = (file) => {
        ruleForm.value.img = ''
        coverMapUrl.value = ''
        imageList.value.splice(0, 1)
        hideUpload.value = imageList.value.length >= 1
        upload.value.handleRemove(file)
      }
	    :on-preview="handlePictureCardPreview"
	    :on-remove="handleRemove"
	  >
	    <img v-if="ruleForm.img" alt="" :src="ruleForm.img" />
	    <el-icon v-else class="avatar-uploader-icon"><plus /></el-icon>
	  </el-upload>
	  <el-dialog v-model="testNameImageVisible">
	    <img :src="testNameImageUrl" style="width: 100%" />
	  </el-dialog>
</el-form-item>

 // 点击图片放大
const handlePictureCardPreview = (file) => {
  testNameImageUrl.value = file.url
  testNameImageVisible.value = true
}
// 上传文件列表删除
const handleRemove = (file) => {
  ruleForm.value.img = ''
  coverMapUrl.value = ''
  imageList.value.splice(0, 1)
  hideUpload.value = imageList.value.length >= 1
  upload.value.handleRemove(file)
}

下载

<el-button
          v-show="scope.row.url !== '' && scope.row.type !== 3"
          class="el-button-text--primary"
          size="small"
          type="text"
          @click="onDownload(scope.row)"
        >
          下载失败数据
</el-button>

const onDownload = (row) => {
    window.open(row.url)
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值