简历相关

原生 Audio、Video;策略模式+动态组件对不同类型消息进行封装 - React

  • 创建 MessageAudio MessageVideo ,用于分别展示聊天消息中的音频和视频
jsx 复制代码
// MessageAudio.js

import React from 'react';

const MessageAudio = ({ src }) => {
  return <audio controls src={src} />;
};

export default MessageAudio;
jsx 复制代码
// MessageVideo.js

import React from 'react';

const MessageVideo = ({ src }) => {
  return <video controls src={src} />;
};

export default MessageVideo;
  • Message 组件:根据消息类型动态渲染相应的消息组件
jsx 复制代码
// Message.js

import React from 'react';
import MessageAudio from './MessageAudio';
import MessageVideo from './MessageVideo';

const Message = ({ type, src }) => {
  // 定义消息类型到组件的映射关系
  const components = {
    audio: MessageAudio,
    video: MessageVideo
  };

  // 根据消息类型获取相应的组件
  const Component = components[type];

  if (!Component) {
    return null;
  }

  return <Component src={src} />;
};

export default Message;
  • ChatApp 组件中遍历消息数组,并将每条消息传递给 Message 组件进行渲染。根据消息的类型不同,Message 组件会动态选择相应的消息组件进行渲染
jsx 复制代码
// ChatApp.js

import React from 'react';
import Message from './Message';

const ChatApp = () => {
  const messages = [
    { type: 'audio', src: 'audio.mp3' },
    { type: 'video', src: 'video.mp4' }
  ];

  return (
    <div>
      {messages.map((message, index) => (
        <Message key={index} type={message.type} src={message.src} />
      ))}
    </div>
  );
};

export default ChatApp;

自定义指令实现按钮级别的权限控制,通过后端返回的字段判断用户角色实现菜单栏权限控制 - Vue,VueRouter,VueX,Element-UI,ES6

  • 名为 permission 的自定义指令,用于按钮级别的权限控制
javascript 复制代码
// permission.js

import Vue from 'vue';

Vue.directive('permission', {
  inserted: (el, binding, vnode) => {
    const { value } = binding;
    const roles = vnode.context.$store.state.roles;
    if (value && !roles.includes(value)) {
      el.parentNode && el.parentNode.removeChild(el);
    }
  }
});
  • 用这个自定义指令,通过 inserted 钩子函数在指令绑定到元素时进行权限判断。如果当前用户的角色不包含在指定的角色列表中,则移除该按钮元素
vue 复制代码
<template>
  <div>
    <!-- 按钮级别的权限控制 -->
    <el-button v-permission="'admin'">Admin Button</el-button>
    <el-button v-permission="'user'">User Button</el-button>

    <!-- 菜单栏权限控制 -->
    <el-menu v-if="roles.includes('admin')">
      <!-- admin 菜单项 -->
    </el-menu>
    <el-menu v-else-if="roles.includes('user')">
      <!-- user 菜单项 -->
    </el-menu>
  </div>
</template>

<script>
export default {
  computed: {
    roles() {
      return this.$store.state.roles;
    }
  }
};
</script>
  • 在应用的根组件中引入 permission 自定义指令
javascript 复制代码
// main.js

import Vue from 'vue';
import App from './App.vue';
import store from './store';
import permissionDirective from './permission';

Vue.config.productionTip = false;

new Vue({
  store,
  render: h => h(App)
}).$mount('#app');

// 注册自定义指令
permissionDirective;

Vue,VueRouter,VueX,Element-UI,ES6 基于UI框架对表格组件进行二次封装,外抛 slot 可进行自定义按钮功能,并实现数据格式化处理配置,支持外部自定义配置修改

vue 复制代码
<!-- CustomTable.vue -->

<template>
  <el-table :data="formattedData" stripe border>
    <!-- 自定义按钮功能插槽 -->
    <template v-if="customButtons" v-slot:action="{ row }">
      <el-button v-for="(button, index) in customButtons" :key="index" @click="handleCustomButtonClick(button, row)">
        {{ button.text }}
      </el-button>
    </template>
    <!-- 根据配置渲染列 -->
    <el-table-column v-for="(column, index) in columns" :key="index" :label="column.label" :prop="column.prop" :formatter="column.formatter">
    </el-table-column>
  </el-table>
</template>

<script>
export default {
  props: {
    data: {
      type: Array,
      required: true
    },
    columns: {
      type: Array,
      required: true
    },
    customButtons: {
      type: Array,
      default: () => []
    }
  },
  computed: {
    formattedData() {
      // 数据格式化处理
      return this.data.map(item => {
        return this.columns.reduce((formattedItem, column) => {
          formattedItem[column.prop] = column.formatter ? column.formatter(item[column.prop]) : item[column.prop];
          return formattedItem;
        }, {});
      });
    }
  },
  methods: {
    handleCustomButtonClick(button, row) {
      // 处理自定义按钮点击事件
      button.handler(row);
    }
  }
};
</script>
  • CustomTable 的 Vue 组件接受三个 prop

    • data:表格数据数组
    • columns:表格列配置数组,包括 label(列标题)、prop(列对应数据字段)、formatter(数据格式化函数)
    • customButtons:自定义按钮功能数组,包括 text(按钮文本)和 handler(按钮点击事件处理函数)
  • 组件内部通过计算属性 formattedData 对传入的原始数据进行格式化处理,然后在表格中渲染

vue 复制代码
<template>
  <custom-table :data="tableData" :columns="tableColumns" :custom-buttons="customButtons">
    <template v-slot:action="{ row }">
      <el-button @click="handleEdit(row)">Edit</el-button>
      <el-button @click="handleDelete(row)">Delete</el-button>
    </template>
  </custom-table>
</template>

<script>
import CustomTable from '@/components/CustomTable.vue';

export default {
  components: {
    CustomTable
  },
  data() {
    return {
      tableData: [
        { id: 1, name: 'Item 1', price: 10 },
        { id: 2, name: 'Item 2', price: 20 },
        { id: 3, name: 'Item 3', price: 30 }
      ],
      tableColumns: [
        { label: 'ID', prop: 'id' },
        { label: 'Name', prop: 'name' },
        { label: 'Price', prop: 'price', formatter: this.formatPrice }
      ],
      customButtons: [
        { text: 'Custom Action', handler: this.handleCustomAction }
      ]
    };
  },
  methods: {
    formatPrice(price) {
      // 价格格式化处理函数
      return `$${price.toFixed(2)}`;
    },
    handleEdit(row) {
      // 编辑操作
      console.log('Edit:', row);
    },
    handleDelete(row) {
      // 删除操作
      console.log('Delete:', row);
    },
    handleCustomAction(row) {
      // 自定义操作
      console.log('Custom Action:', row);
    }
  }
};
</script>
  • CustomTable 组件,并通过 v-slot 插槽插入了自定义的按钮功能
  • 在父组件中定义了 tableDatatableColumnscustomButtons 数据,分别表示表格数据、表格列配置和自定义按钮功能

Axios 进行二次简单封装,配合防抖控制鉴权频率,实现 token 过期之后自动授权并恢复上次请求 - Vue,VueRouter,VueX,Axios,ES6

javascript 复制代码
// api.js

import axios from 'axios';
import router from '@/router';
import store from '@/store';

// 创建 Axios 实例
const instance = axios.create({
  baseURL: 'http://api.example.com',
  timeout: 5000
});

// 请求拦截器
instance.interceptors.request.use(
  config => {
    // 在发送请求之前做些什么
    const token = store.state.token;
    if (token) {
      // 如果存在token,则在请求头中携带token
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  error => {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 响应拦截器
instance.interceptors.response.use(
  response => {
    // 对响应数据做些什么
    return response;
  },
  async error => {
    // 对响应错误做些什么
    if (error.response.status === 401) {
      // 如果是未授权错误,则尝试重新授权
      try {
        await store.dispatch('refreshToken');
        // 重新授权成功后,重新发送之前的请求
        return instance(error.config);
      } catch (error) {
        // 如果重新授权失败,则跳转到登录页面
        router.push('/login');
        return Promise.reject(error);
      }
    }
    return Promise.reject(error);
  }
);

// 导出封装后的 Axios 实例
export default instance;
  • 二次封装名为 instance 的 Axios 实例
  • 在请求拦截器中,判断是否存在 token,如果存在,则在请求头中携带 token
  • 在响应拦截器中,我们捕获了状态码为 401(未授权)的错误,并尝试重新授权
    • 如果重新授权成功,则重新发送之前的请求;如果重新授权失败,则跳转到登录页面
javascript 复制代码
// store.js

import Vue from 'vue';
import Vuex from 'vuex';
import axios from '@/api';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    token: null
  },
  mutations: {
    setToken(state, token) {
      state.token = token;
    }
  },
  actions: {
    async refreshToken({ commit, state }) {
      // 在这里发送重新授权的请求,并更新 token
      try {
        const response = await axios.post('/refresh_token', { token: state.token });
        const newToken = response.data.token;
        commit('setToken', newToken);
      } catch (error) {
        throw error;
      }
    }
  }
});

⾃定义数据 mock ⽅案(React,Typescript,Antd,mobx)

  • 创建一个模拟的后端数据文件 mockData.ts
typescript 复制代码
// mockData.ts

const mockData = [
  { id: 1, name: 'Apple', price: 2.5 },
  { id: 2, name: 'Banana', price: 1.8 },
  { id: 3, name: 'Orange', price: 3.2 },
  { id: 4, name: 'Grapes', price: 4.5 },
  { id: 5, name: 'Watermelon', price: 6.0 }
];

export default mockData;
  • 创建一个 MobX store 来管理数据状态 ProductStore.ts
typescript 复制代码
// ProductStore.ts

import { makeAutoObservable } from 'mobx';
import mockData from './mockData';

interface Product {
  id: number;
  name: string;
  price: number;
}

class ProductStore {
  products: Product[] = [];

  constructor() {
    makeAutoObservable(this);
    // 初始化数据
    this.fetchProducts();
  }

  fetchProducts() {
    // 模拟异步获取数据,实际项目中会替换成真实的后端请求
    setTimeout(() => {
      this.products = mockData;
    }, 1000);
  }
}

const productStore = new ProductStore();
export default productStore;
  • 展示数据并使用 MobX store 中的数据

ProductList.tsx

typescript 复制代码
// ProductList.tsx

import React, { useEffect } from 'react';
import { observer } from 'mobx-react';
import { Table } from 'antd';
import productStore from './ProductStore';

const ProductList: React.FC = () => {
  useEffect(() => {
    productStore.fetchProducts();
  }, []);

  const columns = [
    {
      title: 'ID',
      dataIndex: 'id',
      key: 'id'
    },
    {
      title: 'Name',
      dataIndex: 'name',
      key: 'name'
    },
    {
      title: 'Price',
      dataIndex: 'price',
      key: 'price'
    }
  ];

  return (
    <Table columns={columns} dataSource={productStore.products} loading={!productStore.products.length} />
  );
};

export default observer(ProductList);
  • 在根组件中使用 ProductList 组件
typescript 复制代码
// App.tsx

import React from 'react';
import ProductList from './ProductList';

const App: React.FC = () => {
  return (
    <div>
      <h1>Product List</h1>
      <ProductList />
    </div>
  );
};

export default App;

react采用事件委托的方式获取渲染加入群聊列表

在 React 中,通常不直接使用事件委托,因为 React 提供了更好的方式来处理事件。但是,你可以使用类似事件委托的概念来实现相同的效果,例如在父组件中监听子组件的事件

  • 假设我们有一个 ChatList 组件,它渲染了加入群聊列表中的每个聊天项
jsx 复制代码
// ChatList.js

import React from 'react';
import ChatItem from './ChatItem';

const ChatList = ({ chats }) => {
  return (
    <ul>
      {chats.map((chat, index) => (
        <ChatItem key={index} chat={chat} />
      ))}
    </ul>
  );
};

export default ChatList;

然后,我们有一个 ChatItem 组件,用于渲染单个聊天项,并在点击时触发相应的事件:

jsx 复制代码
// ChatItem.js

import React from 'react';

const ChatItem = ({ chat, onClick }) => {
  const handleClick = () => {
    onClick(chat.id);
  };

  return (
    <li onClick={handleClick}>
      {chat.name}
    </li>
  );
};

export default ChatItem;

现在,我们在父组件中定义一个事件处理函数来处理点击事件,并将其传递给 ChatList 组件:

jsx 复制代码
// ChatApp.js

import React from 'react';
import ChatList from './ChatList';

class ChatApp extends React.Component {
  handleChatItemClick = (chatId) => {
    console.log('Clicked chat item with ID:', chatId);
  };

  render() {
    const chats = [
      { id: 1, name: 'Group Chat 1' },
      { id: 2, name: 'Group Chat 2' },
      { id: 3, name: 'Group Chat 3' }
    ];

    return (
      <div>
        <h2>Join Group Chats</h2>
        <ChatList chats={chats} onClick={this.handleChatItemClick} />
      </div>
    );
  }
}

export default ChatApp;

在这个示例中,我们在 ChatApp 组件中定义了一个事件处理函数 handleChatItemClick,它会在点击聊天项时被调用。然后,我们将这个事件处理函数作为 prop 传递给 ChatList 组件,在 ChatList 组件内部的 ChatItem 组件中调用该事件处理函数。这样,我们就实现了类似事件委托的效果,父组件监听子组件的点击事件。

策略模式

在 React 和 Ant Design(antd)项目中,你可以使用事件代理来处理诸如表单项、列表项等组件的点击事件。以下是一个在 Ant Design 项目中使用事件代理的示例:

假设你有一个 Ant Design 的列表组件,你可以在列表组件的父元素上添加点击事件监听器,然后根据实际点击的元素来执行相应的操作。这个例子中,我们将点击事件委托给列表的父元素,并根据点击的元素来确定是否执行相应的操作。

jsx 复制代码
import React from 'react';
import { List } from 'antd';

class MyList extends React.Component {
  handleClick = (event) => {
    // 检查点击的元素是否是列表项
    if (event.target.tagName === 'LI') {
      // 执行相应的操作,例如获取列表项的内容
      console.log('Clicked item:', event.target.textContent);
    }
  };

  render() {
    return (
      <div onClick={this.handleClick}>
        <List
          dataSource={['Item 1', 'Item 2', 'Item 3']}
          renderItem={item => (
            <List.Item>{item}</List.Item>
          )}
        />
      </div>
    );
  }
}

export default MyList;

DOM 原生属性+API 实现滚动条上下拉加载更多,采用预加载和节流函数实现流畅的无限滚动效果

在 React 和 Ant Design 中实现滚动条上下拉加载更多的功能,同时采用预加载和节流函数实现流畅的无限滚动效果,可以结合使用 onScroll 事件、DOM 原生属性和节流函数

jsx 复制代码
import React, { useState, useEffect } from 'react';
import { List } from 'antd';
import throttle from 'lodash/throttle'; // 导入节流函数

const MyList = () => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    // 模拟初始数据
    setData(Array.from({ length: 10 }, (_, index) => `Item ${index + 1}`));
  }, []);

  const handleScroll = throttle(() => {
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
    const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;

    // 判断是否滚动到底部并且没有正在加载数据
    if (scrollTop + clientHeight >= scrollHeight - 100 && !loading) {
      // 模拟加载更多数据
      setLoading(true);
      setTimeout(() => {
        setData(prevData => [
          ...prevData,
          ...Array.from({ length: 10 }, (_, index) => `Item ${prevData.length + index + 1}`)
        ]);
        setLoading(false);
      }, 1000);
    }
  }, 200);

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, [handleScroll]);

  return (
    <List
      dataSource={data}
      renderItem={item => (
        <List.Item>{item}</List.Item>
      )}
      loading={loading}
    />
  );
};

export default MyList;

echarts仪表盘

ECharts仪表盘(详细示例------附有具体注释)_echarts仪表盘案例-CSDN博客

相关推荐
小白小白从不日白2 小时前
react hooks--useReducer
前端·javascript·react.js
volodyan3 小时前
electron react离线使用monaco-editor
javascript·react.js·electron
等下吃什么?14 小时前
NEXT.js 创建postgres数据库-关联github项目-连接数据库-在项目初始化数据库的数据
react.js
小白小白从不日白17 小时前
react 高阶组件
前端·javascript·react.js
奶糖 肥晨20 小时前
react是什么?
前端·react.js·前端框架
B.-2 天前
Remix 学习 - @remix-run/react 中主要的 hooks
前端·javascript·学习·react.js·web
盼盼盼2 天前
如何避免在使用 Context API 时出现状态管理的常见问题?
前端·javascript·react.js
小白小白从不日白2 天前
react 动画_样式处理
前端·react.js
等下吃什么?3 天前
NEXT.js 中间件 NextResponse.redirect 无效
react.js
小白小白从不日白3 天前
react hooks--useState
前端·javascript·react.js