vue3+tsx+element-plus封装组件总结
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
最近在做vue3+plan+tsx+element-plus的项目tsx在我这里是用来做组件的以往的开发方式是sfc就是vue页面的写法
<template>
</template>
<script>
</script>
<style scoped="scoped" lang="scss">
</style>
自从vue3出来之后舍弃了很多方式比如支持tsx额不解释了我也是差不多知道意思更详情的问度娘我这里讲的就是主要tsx开发的时候碰到的一些问题还有vue3开发的一点总结后续还会继续补充
我的大部分tsx知识都是在 https://zhuanlan.zhihu.com/p/563203507这篇文章里面学到的有兴趣的朋友可以去看看
- tsx支持element-plus里el-table自定义模板<template #default="scope"></template>
这个也是困扰了我很久在百度上找不到的可能现在受众少吧我也是从别人的文章里的蛛丝马迹里面找出来的实现方式如下
这是用sfc方式的写法
<el-table-column label="Date" width="180">
<template #default="scope">
//在这里实现自定义内容参数是 scope比如要自定义显示图片就可以<img :src="scope.row.image"/>
</template>
</el-table-column>
用tsx方式的写法
<el-table-column v-slots={{
default: (props: Record<'scope', string>) =>
//在这里实现自定义内容参数是props比如要自定义显示图片就可以<img :src="props.row.image"/>
}}
/>
解释:v-slots必须我也不知道有没有其他办法就是写在外面就不行)写在标签里面然后用双花括号{{}}写具体代码
default 对应的就是 <template #default="scope"> 里的default
props对应的就是<template #default="scope">里的scope是一个回调的数组
- 支持在<template #default="scope"></template>再声明一个具名插槽并且传这个参数回去
这是我在element-plus的基础上封装的一个组件所以如果需要自定义内容的话还是要把数据给传下去那就要用到作用域插槽了不说了上写法
<el-table-column
v-slots={{
default: (props: Record<'scope', string>) =>
slots.image && slots.image({row:props.row.image})
}}
/>
主要实现是slots.image && slots.image({row:props.row.image})
这相当于sfc的<slot name="image" :row="props.row.image"/>
这是作用域插槽
- v-slots写多个元素比如写几个el-button时还是要用<>包围
v-slots={{
default: (prop: Record<'scope', string>) =>
<>
<el-button size="small">
更新
</el-button>
<el-button type="primary" size="small">
查看
</el-button>
<el-button type="danger" size="small" >
删除
</el-button>
</>
}}
- 那用tsx编写的组件如何导出去并注册全局+局部?
首先要注册成为组件
import { defineComponent,reactive,ref,watch } from "vue";
export default defineComponent({
name: "WayContent",
props,
setup(props, {slots }) {
return ()=>()
}
)}
在vue中将defineComponent拿出
声明name
在setup里面的return写组件页面就是写<div></el-button>这些
setup第一个参数props是父组件传递过来的值第二个参数是context{slots}是从context取出slots属性{slotsemit}就是从context里面取出emit属性
在defineComponent里面的props参数是描述父组件传递过来的值像vue2那样写不过没有默认值了得自己做判断或者用计算属性
全局注册
在main.js或main.ts中
import WayContent from "@/components/WayContent";
const app = createApp(App);
app.component("WayContent", WayContent);
局部注册
在需要得地方
import WayContent from "@/components/WayContent";
然后可以直接使用<WayContent/>,不用再到components里面去注册了不过或许是要在setup语法糖下才能这样写吧没试过就是这样
<script setup lang="ts">
import WayContent from "@/components/WayContent";
</scipt>
- 监听
import { ref,watch } from "vue";
const test = ref()
watch(() => test.value, (newVal) => {
console.log(newVal)
}, {
deep: true,
immediate: true
})
deepimediate这些配置的作用应该和vue2没啥区别就是写法都改成组合式api写的了监听的变量必须要加上.value
- mixin混入
vue3还可以跟vue2一样写mixin就是vue3向下包容的只要没明确舍弃的vue2有的vue3都可以写不过vue3不推荐vue2那种写法了都是倾向于组合式mixin也是如此
context.ts
import { ref,reactive,onMounted,watch } from "vue";
export const context =(gets) => {
// 数据列表
const list = ref()
// 搜索条件
const condition = ref()
// 分页配置
const pagination = ref({
pageNo: 1,
pageSize: 10,
total: 0,
layout: "total, sizes, prev, pager, next, jumper",
handleCurrentChange: (p)=>{
gets2(p,pagination.value.pageSize)
},
handleSizeChange: (p)=>{
gets2(pagination.value.pageNo,p)
}
})
// 获取数据
const gets2 = (pageNo,pageSize) =>{
let c = {};
c.pageNo = pageNo;
c.pageSize = pageSize;
if(condition.value){
for(let k in condition.value){
if(condition.value[k]){
c[k] = condition.value[k]
}
}
}
gets(c).then(res => {
list.value = res.data.data;
pagination.value.total = res.data.total;
})
}
//监听搜索条件的改变当搜索条件改变了就触发请求获取数据
watch(() => condition.value, (newVal) => {
if(newVal){
gets2(1,pagination.value.pageSize)
}
}, {
deep: true,
immediate: true
})
//页面加载完成后请求获取数据
onMounted(() => {
gets2(1,pagination.value.pageSize)
})
return {
list,pagination,gets2,condition
}
}
在需要它的地方
<script setup lang="ts">
import { ref,onMounted,reactive } from "vue";
import { gets } from "@/api/article.ts"
import { context } from "@/mixin/context.ts"
const {list, pagination,condition} = context(gets);
</script>
如上所示
在context.ts里面可以写watch声明响应式变量然后引用的比如list在引用的页面改变它context.ts里面的list也会跟着改变然后也可以传递一个参数比如我是传了一个方法gets进去也都有用他不再像是vue2那样
import context from "@/mixin/context"
export default {
mixin: [context]
}
这种写法了
- 写一个有v-model作用的组件
input.tsx
import { defineComponent,reactive,ref,watch } from "vue";
const props = {
placeholder: { //提示内容
type:String,
},
modelValue: {
type: [String,Number],
required: true,
}
}
export default defineComponent({
name: "WayInput",
props,
emits: ['update:modelValue'],
setup(props, {emit,slots}) {
const modelValue = ref(props.modelValue)
watch(() => modelValue.value, (newVal) => {
emit('update:modelValue', newVal)
}, {
deep: true,
immediate: true
})
watch(() => props.modelValue, (newVal) => {
modelValue.value = newVal
}, {
deep: true,
immediate: true
})
return ()=>(
<div wid="wayInput">
<el-input clearable v-model={modelValue.value} placeholder={props.placeholder || "请输入内容"} />
</div>
)
}
})
使用它
<WayInput v-model="test"/>
import WayInput from "./input.tsx"
import { reactive } from "vue";
const test = reactive()
在input.tsx中主要是以下代码
const props = {
modelValue: {
type: [String,Number], //用来接受父组件的v-model
required: true,
}
}
const modelValue = ref(props.modelValue) //声明一个modelValue并把父组件的v-model值赋予给他
//监听modelValue的变化把值传递给父组件的v-model
watch(() => modelValue.value, (newVal) => {
emit('update:modelValue', newVal)
}, {
deep: true,
immediate: true
})
//监听父组件的v-model变化把值传递给modelValue
watch(() => props.modelValue, (newVal) => {
modelValue.value = newVal
}, {
deep: true,
immediate: true
})
//把modelValue.value绑定给el-input
<el-input clearable v-model={modelValue.value} placeholder={props.placeholder || "请输入内容"} />
扩展如今vue3支持多v-model了还能写函数这些就不再阐述了有兴趣的小伙伴可以去百度了解一下
- 总结暂时完成
另外一些细节的比如refreactive的区别还有setup语法糖等等网上一搜一大把我就不说了还有我在写一个可以传几个参数列表增删查改配置的参数列表就可以实现普通后台管理的搜索展示新增修改删除的组件有兴趣的小伙伴可以收藏我的博客https://www.wayblogs.com/随时欢迎访问来关注我的进度