获取数据:

  1. const rawData = ref([])
  2. onMounted(async () => {
  3. const response = await axios.get('/api/data')
  4. // 假设返回的数据结构类似:[ [item1], [item2], ... ]
  5. rawData.value = response.data
  6. })
  7. 或者:
  8. // 创建响应式数据 fetchList
  9. const newList = ref([]);
  10. const getList = async() => {
  11. // console.log(777721)
  12. // loading.value = true;
  13. await getnewsList()
  14. .then(data => {
  15. // console.log(777722,data.data.titlelist)
  16. // 更新newList的值
  17. newList.value = data.data.titlelist
  18. })
  19. .catch((e) => {
  20. // console.log(777727,e)
  21. // loading.value = false;
  22. });
  23. // console.log(777728)
  24. }
  25. 其中 getnewsList() 方法为:
  26. import { getnewsList } from "@/api/api";
  27. 其中 /api/api 为:
  28. import axios from "@/utils/axios";
  29. /**
  30. * news
  31. */
  32. export function getnewsList(params) {
  33. return axios({
  34. url: "/websiteapi/api/base/lists",
  35. method: "get",
  36. data: params
  37. });
  38. }
  39. 其中 /utils/axios 为:
  40. import axios from "axios";
  41. // import store from "@/store";
  42. // import { ElMessage } from "element-plus";
  43. // import {
  44. // VERSION,
  45. // MODEL_TEST_VERSION,
  46. // SERVER_TYPE,
  47. // AXIOS_TIMEOUT
  48. // } from "@/constant";
  49. // import { switchServerUrl } from "@/utils/index";
  50. /**
  51. * axios请求拦截器
  52. * @param {object} config axios请求配置对象
  53. * @return {object} 请求成功或失败时返回的配置对象或者promise error对象
  54. **/
  55. axios.interceptors.request.use(config => {
  56. return config;
  57. }, error => {
  58. return Promise.reject(error);
  59. });
  60. /**
  61. * axios 响应拦截器
  62. * @param {object} response 从服务端响应的数据对象或者error对象
  63. * @return {object} 响应成功或失败时返回的响应对象或者promise error对象
  64. **/
  65. axios.interceptors.response.use(response => {
  66. return response;
  67. }, error => {
  68. return Promise.reject(error);
  69. });
  70. export default function http(options) {
  71. // 获取不同环境的请求域名
  72. const server_url = 'http://192.168.8.15:222';
  73. let opt = {};
  74. const method = options.method || "post";
  75. const url = options.url;
  76. const data = options.data || {};
  77. if (!options.url) {
  78. console.error("url参数缺失");
  79. return;
  80. }
  81. // if (store.getters.token) {
  82. // data.sys_token = store.getters.token;
  83. // }
  84. if (method == "get") {
  85. opt = {
  86. method,
  87. baseURL: "",
  88. url: url.indexOf("//") > -1 ? url : (server_url + url),
  89. params: data,
  90. timeout: 50000
  91. };
  92. } else if (method == "post") {
  93. opt = {
  94. method,
  95. baseURL: "",
  96. url: url.indexOf("//") > -1 ? url : (server_url + url),
  97. data, // qs.stringify(data)
  98. timeout: 50000
  99. };
  100. }
  101. return new Promise((resolve, reject) => {
  102. axios(opt).then(res => {
  103. // console.log(77770,res);
  104. if (res && (res.status === 200 || res.status === 304 || res.status === 400)) {
  105. const data = res.data;
  106. if (data.code && data.code == 200) {
  107. resolve(data);
  108. } else if (data.code && (data.code == 101 || data.code == 102 || data.code.error == "您还没有登录")) { // 101请获取权限 102登录失效
  109. // ElMessage.error(data.status.error); // 提示错误信息
  110. // 登出操作
  111. // store.dispatch("user/logout");
  112. console.log(data.error);
  113. } else {
  114. // ElMessage.error(data.status.error || "网络异常,请稍后重试!"); // 提示错误信息
  115. reject(data);
  116. }
  117. } else {
  118. // ElMessage.error(res || "网络异常,请稍后重试!"); // 提示错误信息
  119. reject("[lison]网络异常,请稍后重试");
  120. }
  121. }, err => {
  122. // ElMessage.error(err); // 提示错误信息
  123. reject(err);
  124. });
  125. });
  126. }

接口返回的数据分类:

  1. const categorizedData = computed(() => {
  2. const result = {}
  3. for (const group of newList.value) {
  4. // console.log(777731,group.list)
  5. // group 本身也是一个数组 [obj1, obj2, ...]
  6. for (const item of group.list[0]) {
  7. // console.log(777732,item)
  8. const category = item.type
  9. if (!result[category]) {
  10. result[category] = []
  11. }
  12. result[category].push(item)
  13. }
  14. }
  15. // console.log(777735,result)
  16. return result
  17. })

动态生成 tab(切换标签项)

  1. const categories = computed(() => Object.keys(categorizedData.value))

当组件挂载、生命周期钩子

  1. const currentCategory = ref('')
  2. // 当组件挂载时,调用 getList 函数
  3. // 生命周期钩子
  4. // 当一个时:onMounted(getList);
  5. // 当多个时:
  6. onMounted(async () => {
  7. // await tabTitle();
  8. // 在获取数据后调用 newList 函数
  9. await getList();
  10. // 默认选中第一个类别tab
  11. if (categories.value.length > 0) {
  12. currentCategory.value = categories.value[0]
  13. }
  14. });

分页功能

  1. const currentPage = ref(1)
  2. const pageSize = 4
  3. function handleTabChange(cat) {
  4. // console.log('handleTabChange',cat)
  5. currentCategory.value = cat
  6. currentPage.value = 1
  7. }
  8. const pagedData = computed(() => {
  9. const allItems = categorizedData.value[currentCategory.value] || []
  10. const startIndex = (currentPage.value - 1) * pageSize
  11. const endIndex = startIndex + pageSize
  12. // console.log('pagedData',allItems.slice(startIndex, endIndex))
  13. return allItems.slice(startIndex, endIndex)
  14. })

计算总页数

  1. const totalPages = computed(() => {
  2. const allItems = categorizedData.value[currentCategory.value] || []
  3. return Math.ceil(allItems.length / pageSize)
  4. })

点击文章跳转

  1. const goUrl = (url) => open(url)

前端页面渲染示例

  1. <template>
  2. <div class="news">
  3. <y-title en="News updates" cn="新闻动态"></y-title>
  4. <div class="news-tabs">
  5. <div class="news-tabs-li" :class="{ 'news-tabs-li-sd': item === currentCategory }" v-for="item in categories" :key="item" @click="handleTabChange(item)">{{ item }}</div>
  6. </div>
  7. <div class="news-list">
  8. <div class="news-list-li" v-for="item in pagedData" :key="item.id" @click="goUrl(item.url)">
  9. <div class="news-list-li-title">{{ item.title }}</div>
  10. </div>
  11. </div>
  12. <div class="news-navs">
  13. <button class="news-navs-box" @click="currentPage > 1 && (currentPage = currentPage - 1)">上一页</button>
  14. <span class="news-navs-box">{{ currentPage }} / {{ totalPages }}</span>
  15. <button class="news-navs-box" @click="currentPage < totalPages && (currentPage = currentPage + 1)">下一页</button>
  16. </div>
  17. </div>
  18. </template>

样式

  1. <style lang="scss" scoped>
  2. .news {
  3. display: flex;
  4. flex-direction: column;
  5. align-items: center;
  6. margin-top: 120px;
  7. margin-bottom: 270px;
  8. &-tabs {
  9. width: 1360px;
  10. display: flex;
  11. margin-top: 65px;
  12. &-li {
  13. background: #DCE9FF;
  14. width: 250px;
  15. height: 65px;
  16. display: flex;
  17. justify-content: center;
  18. align-items: center;
  19. border-top-left-radius: 10px;
  20. border-top-right-radius: 10px;
  21. margin-right: 15px;
  22. font-size: 30px;
  23. font-weight: bold;
  24. color: #000;
  25. cursor: pointer;
  26. transition: all .3s;
  27. }
  28. &-li-sd {
  29. background: #4A7CEE;
  30. color: #fff;
  31. }
  32. }
  33. &-list {
  34. background: #FAFBFF;
  35. height: 300px;
  36. width: 1360px;
  37. padding: 50px 60px;
  38. box-sizing: border-box;
  39. overflow: hidden;
  40. &-li {
  41. font-size: 24px;
  42. line-height: 24px;
  43. color: #252525;
  44. margin-top: 40px;
  45. cursor: pointer;
  46. &-url {
  47. margin-top: 12px;
  48. }
  49. &:first-child {
  50. margin-top: 0;
  51. }
  52. &:hover {
  53. color: #4A7CEE;
  54. }
  55. }
  56. }
  57. &-navs {
  58. display: flex;
  59. margin-top: 20px;
  60. &-box {
  61. width: 150px;
  62. height: 50px;
  63. background: #DCE9FF;
  64. border-radius: 10px;
  65. margin: 0 10px;
  66. display: flex;
  67. justify-content: center;
  68. align-items: center;
  69. cursor: pointer;
  70. font-size: 24px;
  71. &-sd {
  72. background: #4A7CEE;
  73. color: #fff;
  74. }
  75. }
  76. }
  77. }
  78. </style>