vue3搜索组件封装

需求:基于vue3+ts实现,所有的筛选项是由外部传进来的,组件内部不出现任何业务代码
出现的问题:点击搜索按钮后无法实现搜索功能

//api/users.ts
import request from"@/utils/request"
type Common<T>={
    code: string
    data:T
    mesg: string
    time:string

}

export type Users={
    categoryId:number
    createdBy:string
    createdTime:string
    description:string
    id:number
    name:string
    operatorId:number|null
    selected: boolean
    updatedBy:string
    updatedTime:string
    url:string

}

export type QueriedResult={
    current: number
    hitCount?: false
    optimizeCountSql?:boolean
    orders?:any[]
    pages?:number
    records:Users[]|[]
    searchCount?: boolean
    size:number
    total: number

    

}
export type Condition=Partial<{
    id:number
    size:number
    name:string
    startCreateTime:string
    url:string
    categoryId:string
    endCreateTime: string
    current: number
}>
//分页查询
export const userPage=  (condition:Condition) => {
    return request<Common< QueriedResult>>({
        method:'POST',
        url:'http://39.97.218.60/boss/resource/getResourcePages',
        data: condition,
    })

//composables/users.ts

import { userPage } from "@/api/users";
import type { Condition,QueriedResult } from "@/api/users";
import { ElMessage } from "element-plus";

//查询条件
export const queryCondition=reactive<Condition>({
    size:10,
    name:'',
    url:'',
    categoryId:'',
    current: 1

})

//查询结果
export const queriedResult=ref<QueriedResult>({
    //api/users.ts 里QueryMethod里的冒号前的东西一致
    current: 1,
    records:[],
    size:0,
    total:0,

})
//查询方法
export const queryMethod=async (params:Condition={}) => {
    Object.assign(queryCondition,params)//把两个对象的相同属性合并
    const {data}=await userPage(queryCondition)
    if(data.code==='000000'){
        queriedResult.value=data.data
    }else{
        ElMessage.error("获取资源失败")
        throw new Error("获取资源失败")
    }

 
}

//index.vue
<script setup lang="ts">
import {queriedResult} from '@/composables/users'
import Search from '@/components/search/Search.vue';
import {queryCondition,queryMethod} from '@/composables/users'
import type { FormInstance } from 'element-plus';
import {allResourceCategory,getAllResourceCategory} from '@/composables/category'
import axios from 'axios';
queryMethod()
getAllResourceCategory()
const queryFm=ref<FormInstance>()

const searchDataFn = () => {
  axios
    .post('http://39.97.218.60/boss/resource/getResourcePages', productionlineForm.value)
    .then((response) => {
      queriedResult.value = response.data.records;
    })
    .catch((error) => {
      console.error(error);
    });
};


const searchData = ref([
    {
      label: '姓名',
      type: 'input',
      prop: 'name',
      placeholder: '请输入姓名',
    },
    {
      label: '电话',
      type: 'input',
      prop: 'url',
    },
  ]);

  let productionlineForm = ref({  
  name: '',  
  url:''
})  

const submitEmitsFn = (val) => {  

  productionlineForm.value = val  
  searchDataFn();
    }    





   

</script>

<template>
  <el-card class="box-card">
  <template #header>
    <Search :searchData="searchData" :searchInfo="productionlineForm" @submitEmits="submitEmitsFn"  > 
    </Search>  
 
  </template>

    <el-button size="large">添加</el-button>
    <el-table :data="queriedResult.records"  border style="width: 100%">
    <el-table-column type="index" />
    <el-table-column prop="name" label="姓名"  align="center"/>
    <el-table-column prop="url" label="电话" align="center"/>
    <el-table-column prop="description" label="城市ID" align="center" />
    <el-table-column prop="createdTime" label="年龄" align="center" />
     <el-table-column prop="url" label="专业ID" align="center"/>
     <el-table-column  label="操作" >
        <el-button type="primary">编辑</el-button>
        <el-button type="danger">删除</el-button>
     </el-table-column>
  </el-table>
  </el-card>
</template>

<style scoped>
.el-table{
    margin-top: 17px;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.text {
  font-size: 14px;
}

.item {
  margin-bottom: 18px;
}

</style>


//Search.vue
<template>
  <el-form :model="searchInfo">
    <el-row :gutter="10" style="margin: 10px 0;">
      <el-col :span="item.span || 6" v-for="item, i in searchData" :key="i">
        <el-form-item :label="item.label" :label-width="item.width || '80px'">
          <el-input v-if="item.type === 'input'" v-model="searchInfo[item.prop]"
            :placeholder="item.placeholder || '请输入'"  clearable/>
          <el-select v-if="item.type === 'select'" v-model="searchInfo[item.prop]"
            :placeholder="item.placeholder || '请选择'" clearable>
         
            <el-option v-for="item2: {label: string, value: any} in item.options" :key="i2" :label="item2.label" :value="item2.value" />
          </el-select>
          <el-date-picker v-if="item.type === 'date'" type="date" :value-format="item.format || 'YYYY-MM-DD'"
            :placeholder="item.placeholder || '请选择日期'" v-model="searchInfo[item.prop]"
            style="width: 100%;" clearable></el-date-picker>
        </el-form-item>
      </el-col>
 
      <el-col :span="btnInfo.span || 6">
        <el-row justify="end">
          <el-button :type="btnInfo.query || 'primary'" @click="onSubmit('query')">查询</el-button>
          <el-button :type="btnInfo.reset || 'default'" @click="onSubmit('reset')">重置</el-button>
        </el-row>
      </el-col>
    </el-row>
  </el-form>
</template>
 
<script setup lang="ts">
interface SearchItem {  
  span?: number;  
  label: string;  
  type: string;  
  prop: string;  
  options?: { label: string, value: any }[];  
  width?: string;  
  placeholder?: string;  
  format?: string;  
}  

interface ButtonInfo {  
  span?: number;  
  query?: string;  
  reset?: string;  
}  



const props = defineProps({
  //搜索信息
  searchInfo: {
    type: Object,
    default: {},
    required: true
  },
  //表单数组
  searchData: {
    type: Array,
    default: [],
    required: true
  },
  //按钮信息
  btnInfo: {
    type: Object,
    default: {},
    required: true
  }
})
 
const emit = defineEmits(['submitEmits']);
const onSubmit = (data) => {
  if (data == 'reset') {
    emit('submitEmits', {});
  } else if (data === 'query') {
    emit('submitEmits', props.searchInfo);

  }
 
}
</script>
 
<style lang="scss" scoped></style>


请问如何修改,并写出修改后的具体代码

引用 皆我百晓生 小程序回复内容作答:

根据问题描述,你想要实现一个基于Vue3 + TypeScript的搜索组件封装,并且所有的筛选项都由外部传递进来,组件内部不包含任何业务代码。你已经尝试过一些代码,但是在点击搜索按钮后无法实现搜索功能。

为了解决这个问题,首先需要将搜索按钮点击事件的处理函数submitEmitsFn修改为调用queryMethod来进行搜索。另外,由于你使用的是Vue3的Composition API,在Search.vue中需要使用setup语法进行组件的逻辑处理。

下面是调整后的代码:

// Search.vue
<template>
  <el-form :model="searchInfo">
    <el-row :gutter="10" style="margin: 10px 0;">
      <el-col :span="item.span || 6" v-for="item, i in searchData" :key="i">
        <el-form-item :label="item.label" :label-width="item.width || '80px'">
          <el-input v-if="item.type === 'input'" v-model="searchInfo[item.prop]"
            :placeholder="item.placeholder || '请输入'" clearable />
          <el-select v-if="item.type === 'select'" v-model="searchInfo[item.prop]"
            :placeholder="item.placeholder || '请选择'" clearable>
            <el-option v-for="item2 in item.options" :key="item2.value" :label="item2.label" :value="item2.value" />
          </el-select>
          <el-date-picker v-if="item.type === 'date'" type="date" :value-format="item.format || 'yyyy-MM-dd'"
            :placeholder="item.placeholder || '请选择日期'" v-model="searchInfo[item.prop]"
            style="width: 100%;" clearable></el-date-picker>
        </el-form-item>
      </el-col>

      <el-col :span="btnInfo.span || 6">
        <el-row justify="end">
          <el-button :type="btnInfo.query || 'primary'" @click="onSubmit('query')">查询</el-button>
          <el-button :type="btnInfo.reset || 'default'" @click="onSubmit('reset')">重置</el-button>
        </el-row>
      </el-col>
    </el-row>
  </el-form>
</template>

<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';

interface SearchItem {
  span?: number;
  label: string;
  type: string;
  prop: string;
  options?: { label: string; value: any }[];
  width?: string;
  placeholder?: string;
  format?: string;
}

interface ButtonInfo {
  span?: number;
  query?: string;
  reset?: string;
}

const props = defineProps({
  // 搜索信息
  searchInfo: {
    type: Object,
    default: () => ({}),
    required: true
  },
  // 表单数组
  searchData: {
    type: Array as () => SearchItem[],
    default: () => [],
    required: true
  },
  // 按钮信息
  btnInfo: {
    type: Object as () => ButtonInfo,
    default: () => ({}),
    required: true
  }
});

const emit = defineEmits(['submitEmits']);

const onSubmit = (data: string) => {
  if (data === 'reset') {
    emit('submitEmits', {});
  } else if (data === 'query') {
    emit('submitEmits', props.searchInfo);
  }
};
</script>

<style lang="scss" scoped></style>
<!-- index.vue -->
<template>
  <el-card class="box-card">
    <template #header>
      <Search :searchData="searchData" :searchInfo="productionlineForm" @submitEmits="submitEmitsFn"></Search>
    </template>

    <el-button size="large">添加</el-button>
    <el-table :data="queriedResult.records" border style="width: 100%">
      <el-table-column type="index" />
      <el-table-column prop="name" label="姓名" align="center" />
      <el-table-column prop="url" label="电话" align="center" />
      <el-table-column prop="description" label="城市ID" align="center" />
      <el-table-column prop="createdTime" label="年龄" align="center" />
      <el-table-column prop="url" label="专业ID" align="center" />
      <el-table-column label="操作">
        <el-button type="primary">编辑</el-button>
        <el-button type="danger">删除</el-button>
      </el-table-column>
    </el-table>
  </el-card>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
import Search from '@/components/search/Search.vue';
import { queryMethod, queriedResult } from '@/composables/users';
import { ElMessage } from 'element-plus';
import axios from 'axios';

const searchData = ref([
  {
    label: '姓名',
    type: 'input',
    prop: 'name',
    placeholder: '请输入姓名'
  },
  {
    label: '电话',
    type: 'input',
    prop: 'url'
  }
]);

const productionlineForm = ref({
  name: '',
  url: ''
});

const submitEmitsFn = (val: any) => {
  productionlineForm.value = val;
  queryMethod(productionlineForm.value); // 调用 queryMethod 函数进行搜索
};

queryMethod(); // 初始化时进行一次搜索
</script>

<style scoped>
.el-table {
  margin-top: 17px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.text {
  font-size: 14px;
}

.item {
  margin-bottom: 18px;
}
</style>

修改后的代码将搜索按钮的点击事件处理函数submitEmitsFn改为调用queryMethod函数,并将productionlineForm.value作为参数传递给queryMethod函数进行搜索。另外,在页面初始化时也调用了queryMethod函数进行一次搜索。

希望这个回答对你有帮助,如果还有任何问题,请随时继续追问。

在index.vue中,你同时使用了composables/users.ts中的queryMethod和一个新的searchDataFn函数来实现搜索功能。

你可以尝试修改index.vue的代码如下:

const searchDataFn = async () => {
  await queryMethod(productionlineForm.value)
};

然后在Search.vue中的el-button上绑定搜索函数,如下:

<el-button :type="btnInfo.query || 'primary'" @click="onSubmit('query', searchDataFn)">查询</el-button>

这样就可以将搜索功能集成到queryMethod中,通过调用该方法来实现搜索。

同时,要注意修改Search.vue中onSubmit函数的参数为两个,以支持传入新的searchDataFn函数。

const onSubmit = (data, fn) => {
  if (data == 'reset') {
    emit('submitEmits', {});
  } else if (data === 'query') {
    fn();
  }
}

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
根据你提供的代码,我看到一些需要修改的地方。首先,在Search.vue组件中,你定义了一个onSubmit方法,但是没有调用它。你需要在查询和重置按钮的点击事件中调用onSubmit方法,将对应的参数传递进去。
修改后的Search.vue组件代码如下:

<template>
  <el-form :model="searchInfo">
    <el-row :gutter="10" style="margin: 10px 0;">
      <el-col :span="item.span || 6" v-for="item, i in searchData" :key="i">
        <el-form-item :label="item.label" :label-width="item.width || '80px'">
          <el-input v-if="item.type === 'input'" v-model="searchInfo[item.prop]"
            :placeholder="item.placeholder || '请输入'"  clearable/>
          <el-select v-if="item.type === 'select'" v-model="searchInfo[item.prop]"
            :placeholder="item.placeholder || '请选择'" clearable>
         
            <el-option v-for="item2 in item.options" :key="item2.value" :label="item2.label" :value="item2.value" />
          </el-select>
          <el-date-picker v-if="item.type === 'date'" type="date" :value-format="item.format || 'YYYY-MM-DD'"
            :placeholder="item.placeholder || '请选择日期'" v-model="searchInfo[item.prop]"
            style="width: 100%;" clearable></el-date-picker>
        </el-form-item>
      </el-col>
 
      <el-col :span="btnInfo.span || 6">
        <el-row justify="end">
          <el-button :type="btnInfo.query || 'primary'" @click="onSubmit('query')">查询</el-button>
          <el-button :type="btnInfo.reset || 'default'" @click="onSubmit('reset')">重置</el-button>
        </el-row>
      </el-col>
    </el-row>
  </el-form>
</template>
 
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';

interface SearchItem {  
  span?: number;  
  label: string;  
  type: string;  
  prop: string;  
  options?: { label: string, value: any }[];  
  width?: string;  
  placeholder?: string;  
  format?: string;  
}  
 
interface ButtonInfo {  
  span?: number;  
  query?: string;  
  reset?: string;  
}  
 
const props = defineProps({
  // 搜索信息
  searchInfo: {
    type: Object,
    default: () => ({}),
    required: true
  },
  // 表单数组
  searchData: {
    type: Array,
    default: () => [],
    required: true
  },
  // 按钮信息
  btnInfo: {
    type: Object,
    default: () => ({}),
    required: true
  }
});

const emit = defineEmits(['submitEmits']);

const onSubmit = (data) => {
  if (data === 'reset') {
    emit('submitEmits', {});
  } else if (data === 'query') {
    emit('submitEmits', props.searchInfo);
  }
};
</script>

接下来,在index.vue组件中,你使用了axios库发送了一个独立的请求来获取搜索结果,而不是调用封装好的queryMethod方法进行查询。你应该使用queryMethod方法进行查询,并且在搜索按钮的点击事件中调用该方法。

修改后的index.vue组件代码如下:

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import Search from '@/components/search/Search.vue';
import { queryCondition, queryMethod } from '@/composables/users';
import { ElMessage } from 'element-plus';

onMounted(queryMethod);

const searchData = ref([
  {
    label: '姓名',
    type: 'input',
    prop: 'name',
    placeholder: '请输入姓名',
  },
  {
    label: '电话',
    type: 'input',
    prop: 'url',
  },
]);

const productionlineForm = ref({  
  name: '',  
  url: ''
});

const submitEmitsFn = (val) => {  
  productionlineForm.value = val;  
  queryMethod();
};
</script>

<template>
  <el-card class="box-card">
    <template #header>
      <Search
        :searchData="searchData"
        :searchInfo="productionlineForm"
        :btnInfo="{ query: 'primary', reset: 'default' }"
        @submitEmits="submitEmitsFn"
      />
    </template>
    <div>查询结果展示</div>
  </el-card>
</template> 

通过以上修改,你应该能够使用queryMethod方法进行查询,并且在点击查询按钮时触发查询操作。同时,重置按钮也应该能够正确地重置搜索条件。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

参考结合GPT4.0、文心一言,如有帮助,恭请采纳。

这里可能有几个潜在的问题:

1、productionlineForm.value在提交表单的时候是否已经被正确赋值?你可以在submitEmitsFn函数内部打印出productionlineForm.value来查看其值。
2、在searchDataFn函数中,你使用了productionlineForm.value作为请求的参数,但是你的searchData定义中并没有这个值。你应该检查一下你的表单数据productionlineForm.value是否包含了你需要的字段。
3、在axios请求返回后,你尝试将返回的数据设置为queriedResult.value,但是在你的代码中并没有定义queriedResult。你应该在你的代码中定义这个值。
4、在你的模板中,你使用了queriedResult.records作为表格的数据源,但是在你的代码中并没有定义queriedResult。你应该在你的代码中定义这个值。
5、你应该检查你的后端接口是否正常工作,返回的数据格式是否符合你的预期。


<template>
  <el-form :model="searchInfo">
    <el-row :gutter="10" style="margin: 10px 0;">
      <el-col :span="item.span || 6" v-for="item, i in searchData" :key="i">
        <el-form-item :label="item.label" :label-width="item.width || '80px'">
          <el-input v-if="item.type === 'input'" v-model="searchInfo[item.prop]"
            :placeholder="item.placeholder || '请输入'"  clearable/>
          <el-select v-if="item.type === 'select'" v-model="searchInfo[item.prop]"
            :placeholder="item.placeholder || '请选择'" clearable>
            <el-option v-for="item2 in item.options" :key="item2.value" :label="item2.label" :value="item2.value" />
          </el-select>
          <el-date-picker v-if="item.type === 'date'" type="date" :value-format="item.format || 'YYYY-MM-DD'"
            :placeholder="item.placeholder || '请选择日期'" v-model="searchInfo[item.prop]"
            style="width: 100%;" clearable></el-date-picker>
        </el-form-item>
      </el-col>
      <el-col :span="btnInfo.span || 6">
        <el-row justify="end">
          <el-button :type="btnInfo.query || 'primary'" @click="onSubmit('query')">查询</el-button>
          <el-button :type="btnInfo.reset || 'default'" @click="onSubmit('reset')">重置</el-button>
        </el-row>
      </el-col>
    </el-row>
  </el-form>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';
interface SearchItem {  
  span?: number;  
  label: string;  
  type: string;  
  prop: string;  
  options?: { label: string, value: any }[];  
  width?: string;  
  placeholder?: string;  
  format?: string;  
}  
interface ButtonInfo {  
  span?: number;  
  query?: string;  
  reset?: string;  
}  
const props = defineProps({
  // 搜索信息
  searchInfo: {
    type: Object,
    default: () => ({}),
    required: true
  },
  // 表单数组
  searchData: {
    type: Array,
    default: () => [],
    required: true
  },
  // 按钮信息
  btnInfo: {
    type: Object,
    default: () => ({}),
    required: true
  }
});
const emit = defineEmits(['submitEmits']);
const onSubmit = (data) => {
  if (data === 'reset') {
    emit('submitEmits', {});
  } else if (data === 'query') {
    emit('submitEmits', props.searchInfo);
  }
};
</script>


【相关推荐】





如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^