模拟实现console.dir函数

本文介绍了一个使用JavaScript实现的对象属性遍历与显示方法,通过递归方式展示对象的属性和方法,并支持折叠展开功能。此外,还介绍了如何对属性进行排序以提高可读性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


function dir(obj,name,initContainer){
var ul = initContainer ? initContainer : document.createElement("ul");
var li = document.createElement("li");
var span = document.createElement("span");
span.innerHTML = "+"
span.className = "plus";
span.onclick = function(){
if(this.rendered){
if(this.className === "minus"){
this.className = "plus";
this.innerHTML = "+"
this.parentNode.lastChild.style.display = "block";
}else{
this.className = "minus";
this.innerHTML = "-"
this.parentNode.lastChild.style.display = "none";
}
return ;
}
var ul = document.createElement("ul");
for(var k in obj){
dir(obj[k],k,ul)
}
li.appendChild(ul);

this.className = "minus";
this.innerHTML = "-"
this.rendered = true;
}
li.appendChild(span);
var span2 = document.createElement("span");
name = name || obj.toString();
span2.innerHTML = name + " : " + typeof obj;
li.appendChild(span2);
ul.appendChild(li);
return ul
}

/*-----------------------------Test dir--------------------------------*/
window.onload = function(){
document.body.appendChild(dir(window));
}

测试打印出window对象的所有属性和方法,见附件。

另外还可以排序,以下按属性和方法的名称排序(当然也可以按照typeof类型排序):

var properties = [];
for(var p in obj){
properties.push(p);
}
properties.sort();
var len = properties.length;
for(var i=0;i<len;i++){
dir(obj[properties[i]],properties[i],ul)
}
li.appendChild(ul);
import React, { useState, useEffect, useCallback, useMemo } from "react"; import { JsonForms } from "@jsonforms/react"; import { materialCells, materialRenderers } from '@jsonforms/material-renderers'; import EnumSelectRenderer, { EnumSelectRendererTester } from '../../renderer/EnumSelectRenderer'; import BaseRenderer, { BaseRendererTester } from '../../renderer/BaseRenderer'; import { vanillaCells, vanillaRenderers, vanillaStyles, JsonFormsStyleContext, } from "@jsonforms/vanilla-renderers"; import { useTranslation } from "react-i18next"; import formSchema from "./form-schema.json"; import formUischema from "./form-ui-schema.json"; import liststyle from "../../../style/design-system-form.json"; import '../style/global.css'; import '../style/S-ECSCM.css'; import "tabulator-tables/dist/css/tabulator.min.css"; import { ReactTabulator, ReactTabulatorOptions } from 'react-tabulator'; import { useUnifiedForm } from '../../../yupCommon/useUnifiedForm'; import { useYupI18n } from '../../../yupCommon/useYupI18n'; import { createValidationSchema } from './validationSchemas'; import initdata from './table-data.json'; const tableData = initdata["table"]; const styleContextValue = { styles: [...vanillaStyles, ...liststyle] }; import { rankWith, scopeEndsWith, and, or, schemaTypeIs } from '@jsonforms/core'; import useProtectedNavigate from "../../../services/useProtectedNavigate"; import * as Yup from "yup"; import $ from 'jquery'; import { useHttpClient } from '../../httpClient'; import { useUserData } from '../../../UserContext'; const sampleData = { "number": "111", "parts": "222", "partsid": "", "products": "", "productsid": "", "shop": "", "shopid": "", "status-category": "", "survey-category": ["test1", "test2"], "request-category": "", "request-dept": "", "request-person": "", "requestdate_min": "", "requestdate_max": "", "expected_response_min": "", "expected_response_max": "", "response_date_min": "", "response_date_max": "" }; const SECSCMTEST = () => { const { t: translation, i18n: i18nInstance } = useTranslation(); const locale = i18nInstance.language; const protectedNavigate = useProtectedNavigate(); const [statusSelected, setStatusSelected] = useState(false); const tableRef = React.useRef<{table?: Tabulator;}>(null); const [tableData, setTableData] = useState([]); const [totalRecords, setTotalRecords] = useState(0); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(0); // 使用多语言 Yup 配置 const { createLabeledSchema, currentLang } = useYupI18n(); // 创建多语言验证 schema const validationSchema = useMemo(() => { const baseSchema = createValidationSchema(currentLang); return createLabeledSchema(baseSchema); }, [createLabeledSchema, currentLang]); // 使用改进后的统一表单管理(现在支持输入法兼容和多语言) const { formData, validationErrors, isValid, isSubmitting, updateFormData, updateField, registerField, getFieldValue, getFieldError, resetForm, submitForm } = useUnifiedForm({ schema: validationSchema, initialData: sampleData, debounceMs: 500, // 设置防抖延迟为500ms onSubmit: (data) => { console.log("表单提交数据:", data); alert("表单校验通过,数据提交成功!"); } }); // 添加画面变更时触发的方法,将错误消息放到 validation input-description 中 const updateValidationMessages = useCallback(() => { const validationElements = document.getElementsByClassName('validation'); Array.from(validationElements).forEach(element => { element.innerHTML = ''; }); Object.entries(validationErrors).forEach(([field, error]) => { // 修正:使用正确的模板字符串语法和原生 DOM API const controlDiv = document.querySelector(`div[id*="${field}"]`); if (controlDiv) { // 在控制容器中查找验证消息容器 const validationDiv = controlDiv.querySelector('.validation'); if (validationDiv) { // 更新错误消息内容和样式 validationDiv.textContent = error || ''; const htmlElement = validationDiv as HTMLElement; if (error) { htmlElement.style.color = '#ff4444'; htmlElement.style.fontSize = '12px'; htmlElement.style.marginTop = '4px'; htmlElement.style.fontWeight = '400'; htmlElement.style.display = 'block'; } else { htmlElement.style.color = ''; htmlElement.style.fontSize = ''; htmlElement.style.marginTop = ''; htmlElement.style.fontWeight = ''; htmlElement.style.display = 'none'; } } } }); }, [getFieldError]); const httpClient = useHttpClient(); const getTableData = (page) => { var obj: any = {}; const numbers = $("select[id^='#/properties/number']"); if(numbers.length != 0){ obj['number'] = $("select[id^='#/properties/number']")[0].value; }else{ obj['number'] = null; } obj['page'] = page; obj['size'] = 10; httpClient.post('/SECSCMTEST/getTableData', obj) .then(response => { console.log('success:', response.data); setTableData(response.data.table || []); setTotalRecords(response.data.total || 0); // 保存总记录数 setCurrentPage(page); // 在获取数据后更新最大页数 if (tableRef.current) { const maxPage = Math.ceil((response.data.total || 0) / 10); try { // 尝试不同的方法设置最大页数 if (tableRef.current.setMaxPage) { tableRef.current.setMaxPage(maxPage); } else if (tableRef.current.modules && tableRef.current.modules.page) { tableRef.current.modules.page.setMaxPage(maxPage); } console.log('设置最大页数成功:', maxPage); } catch (error) { console.error('设置最大页数失败:', error); } } }) .catch(error => { console.error('Save failed:', error); }); }; const { userData } = useUserData(); useEffect(() => { if(userData && userData.role){ getTableData(1); } }, []); // 监听 validationErrors 变化,自动更新错误消息显示 useEffect(() => { // 使用 setTimeout 确保 DOM 已经渲染完成 const timer = setTimeout(() => { updateValidationMessages(); }, 100); return () => clearTimeout(timer); }, [validationErrors, updateValidationMessages]); useEffect(() => { if (tableRef.current && tableRef.current.table) { const tabulator = tableRef.current.table; setTimeout(() => { try { tabulator.setColumns(statusSelected ? Columns1 : Columns2); } catch (error) { console.error("Failed to refresh table:", error); } }, 100); } }, [statusSelected]); const cellClickFunc = (_e: any, cell: any) => { const _rowdata = cell.getRow().getData(); const _investigation_no = _rowdata.investigation_no; const _investigation_status = _rowdata.investigation_status; const _representative_supplier_name = _rowdata.representative_supplier_name; if (_investigation_no && _investigation_status && _representative_supplier_name) { protectedNavigate(`/SECSCM005?no=${_investigation_no}&status=${_investigation_status}&date=${_representative_supplier_name}`) } else { console.error("Row data is missing required fields for navigation:", _rowdata); } } const baseColumnConfig = { headerHozAlign: 'center' as const, hozAlign: 'left' as const, vertAlign: 'center' as const, cellClick: (_e: any, cell: any) => { cellClickFunc(_e, cell) } }; const Columns1 = [ { title: 'ID', formatter: "rownum", hozAlign: "center" as const, headerHozAlign: "center" as const, width: 40, headerSort: false }, { title: "", formatter: "rowSelection", titleFormatter: "rowSelection", hozAlign: "center" as const, headerHozAlign: "center" as const, headerSort: false, width: 40 }, { ...baseColumnConfig, title: '調査依頼ID', field: 'investigation_no'}, { ...baseColumnConfig, title: '調査対象', field: 'representative_part_name'}, { ...baseColumnConfig, title: '依頼区分', field: 'representative_part_id'}, { ...baseColumnConfig, title: '依頼部門', field: 'purchased_item_name'}, { ...baseColumnConfig, title: '回答希望日', field: 'representative_supplier_name'}, { title: "个人信息", headerHozAlign: 'center' as const, columns: [ { ...baseColumnConfig, title: '最短回答予定日', field: 'representative_supplier_id'}, { ...baseColumnConfig, title: '最長回答予定日', field: 'investigation_status'}, ] }, { ...baseColumnConfig, title: '依頼担当者', field: 'purchased_item_id'}, ]; const Columns2 = [ { title: "", formatter: "rowSelection", titleFormatter: "rowSelection", hozAlign: "center" as const, headerHozAlign: "center" as const, headerSort: false, width: 40 }, { ...baseColumnConfig, title: '調査依頼ID', field: 'investigation_no'}, { ...baseColumnConfig, title: '調査対象', field: 'representative_part_name'}, { ...baseColumnConfig, title: '依頼区分', field: 'representative_part_id'}, { ...baseColumnConfig, title: '依頼部門', field: 'purchased_item_name'}, { ...baseColumnConfig, title: '回答希望日', field: 'representative_supplier_name'}, { ...baseColumnConfig, title: '最短回答予定日', field: 'representative_supplier_id'}, { ...baseColumnConfig, title: '最長回答予定日', field: 'investigation_status'}, { ...baseColumnConfig, title: '依頼担当者', field: 'purchased_item_id'}, ]; const handleFormChange = useCallback((data: any) => { updateFormData(data); setStatusSelected(data["status-category"] && data["status-category"] !== ""); // 表单数据变化时也更新验证消息 setTimeout(() => { updateValidationMessages(); }, 100); }, [updateFormData, updateValidationMessages]); const handleClearForm = () => { resetForm(); }; const ErrorMessage = ({ fieldName }: { fieldName: keyof typeof sampleData }) => { const error = getFieldError(fieldName); return error ? <div style={{ color: "red", fontSize: "12px", marginTop: "2px" }}>{error}</div> : null; }; // 远程数据加载函数 const fetchRemoteData = (url, config, params) => { return new Promise((resolve, reject) => { // 模拟 API 参数(实际项目替换为真实 API) const queryParams = new URLSearchParams({ page: params.page, size: params.size, sort: params.sorters.map(s => `${s.field}:${s.dir}`).join(',') }); // 实际项目使用 fetch/axios 替换此部分 setTimeout(() => { const mockData = { last_page: 5, data: Array.from({ length: params.size }, (_, i) => ({ representative_part_id: i + (params.page - 1) * params.size, investigation_no: `用户 ${i + 1}`, representative_part_name: `user${i + 1}@example.com`, representative_supplier_name: `职位 ${Math.floor(Math.random() * 10)}` })) }; resolve(mockData); }, 500); }); }; const options: ReactTabulatorOptions = { renderHorizontal: "virtual", layout: "fitDataTable", selectable: true, pagination: "remote", paginationSize: 10, // 远程分页控制属性 page: 1, // 当前页码 paginationSizeSelector: [10, 25, 50, 100], // 可选的每页条数 // 分页回调函数 //pageLoaded: (pageno: number) => { // if (pageno !== currentPage) { // getTableData(pageno); // } //}, ajaxRequestFunc: fetchRemoteData, ajaxResponse: function(url, params, response) { return { data: response.data, last_page: response.last_page }; } }; const renderers = [ ...vanillaRenderers, { tester: BaseRendererTester, renderer: BaseRenderer } //{ tester: EnumSelectRendererTester, renderer: EnumSelectRenderer } ]; // 修改测试函数,尝试多种方法 const checkTableRef = () => { console.log('手动检查 tableRef:'); console.log('tableRef.current:', tableRef.current); if (tableRef.current) { console.log('找到 Tabulator 实例'); console.log('可用方法:', Object.getOwnPropertyNames(tableRef.current.current)); console.log('modules:', tableRef.current.modules); const maxPage = Math.ceil(totalRecords / 10); console.log('计算的最大页数:', maxPage); // 尝试多种设置方法 try { if (tableRef.current.current.setMaxPage) { tableRef.current.current.setMaxPage(maxPage); console.log('方法1成功: setMaxPage'); } else if (tableRef.current.modules && tableRef.current.modules.page) { if (tableRef.current.modules.page.setMaxPage) { tableRef.current.modules.page.setMaxPage(maxPage); console.log('方法2成功: modules.page.setMaxPage'); } } else { // 尝试重新设置选项 const newOptions = { ...options, maxPage }; console.log('尝试重新设置选项:', newOptions); } } catch (error) { console.error('所有方法都失败:', error); } } }; return ( <div id="content"> <br /> <details className="details"> <summary className="details-summary">{translation('common.button.show-select-menu.label','no label')}</summary> <form onSubmit={submitForm}> {/* JsonForms 部分 */} <div style={{ marginBottom: "20px" }}> <JsonFormsStyleContext.Provider value={styleContextValue}> <JsonForms i18n={{locale: locale, translate: (key: string, defaultMessage?: string) => translation(key, defaultMessage || '')}} schema={formSchema} uischema={formUischema} data={formData} renderers={renderers} cells={vanillaCells} onChange={({ data }) => handleFormChange(data)} validationMode="NoValidation" /> </JsonFormsStyleContext.Provider> </div> {/* 原生HTML表单部分 - 现在支持输入法兼容 */} <div style={{ border: "1px solid #fff"}}> <div className="control" id="#/properties/tel"> <label htmlFor="tel-input" className="label">电话:</label> <input className="validate valid input text-field" id="tel-input" name="tel" type="text" ref={(ref) => registerField('tel', ref)} defaultValue={getFieldValue('tel')} /> <ErrorMessage fieldName="tel" /> </div> </div> <div id="button-right"> <input type="button" className="button" style={{ marginRight: "20px" }} value={translation('common.button.clear.label','no label')} onClick={handleClearForm} /> <input type="submit" className="button" value={translation('common.button.select.label','no label')} disabled={!isValid || isSubmitting} style={{ opacity: (isValid && !isSubmitting) ? 1 : 0.5 }} /> {/* 添加测试按钮 */} <input type="button" className="button" style={{ marginLeft: "20px", backgroundColor: "#ff6600" }} value="测试tableRef" onClick={checkTableRef} /> </div> </form> </details> <br /> <div> <ReactTabulator onRef={(instance) => { tableRef.current = instance; }} columns={Columns2 as any} data={[]} options={options} /> </div> <div style={{ marginTop: "10px" }}> <input className="button" type="button" style={{ marginRight: "30px" }} value={translation('common.button.select-all.label','no label')} /> <input type="button" className="button" value={translation('common.button.CSV-download.label','no label')} /> </div> </div> ); }; export default SECSCMTEST; 找出我这个文件的错误
最新发布
07-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值