前端面试手写to do list

今天遇到一件令我有点气愤的事情,大致的事情经过是这样的,昨天晚上九点多的时候接到一个电话面试,是一个hr姐姐,她和我聊了10多分钟,我介绍了下我的技术栈,以及我曾经做过的某些业务,最后hr姐姐说她这边面试通过了,然后后面会有一轮面试题考核,需要线上做完发代码给她,让技术考核,考核通过了之后线下面试。 然后昨天晚上我搞一个外包项目折腾到了凌晨四点
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
然后顶着困意实现完之后,把代码发给他了,我个人测试效果都是没有问题的,虽然有些代码确实可以再优化,当时害怕时间超时,有些地方就没考虑太多,大概过了三个小时,hr姐姐说代码审核没通过,我想问原因,hr姐姐给我发了这样一张图
在这里插入图片描述
当时看完我就有点气愤了,搜索功能是我没有注意,但是他后面说的使用原生js的实现方式效率低,然后就给我扣上了个前端开发经验不足的帽子。
一个小小的to do list,我不用moment处理日期格式化,不用element-plus的form组件来进行表单校验,看漏了一个功能就能代表这些吗?
而且我应聘的是8k的前端岗位。我个人的技术栈,底层html+css+js,h5+css3,es6,promise,工程化(es module,common js),vue2,vue3,微信小程序,uniapp,后端熟悉nodejs,express,egg,怎么说也是一个能够独立开发前后端的开发者,感觉给说的一文不值,还不如别人刚应届出来的实习生。

下面放我写的代码吧

大致的项目结构

在这里插入图片描述

具体代码

main.ts

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App);
app.use(ElementPlus)
app.mount('#app')

App.vue

<template>
  <TodoList></TodoList>
</template>

<script lang="ts">
import TodoList from './components/TodoList.vue'
export default {
  components : {
    TodoList
  }
}
</script>

<style>

</style>

util/index.ts

export function timeFormat(date:any, isDateOnly = false) {
    let Y = date.getFullYear();
    let M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1);
    let D = date.getDate() < 10 ? ('0' + date.getDate()) : date.getDate();
    let hours = date.getHours()
    let minutes = date.getMinutes() < 10 ? ('0' + date.getMinutes()) : date.getMinutes()
    let seconds = date.getSeconds() < 10 ? ('0' + date.getSeconds()) : date.getSeconds()
    if (isDateOnly) {
        date = Y + '-' + M + '-' + D;
    } else {
        date = Y + '-' + M + '-' + D + ' ' + hours + ':' + minutes + ':' + seconds;
    }

    return date;
}

TodoList.vue

<template>
  <div class="todo-list-container">
    <div class="op-container">
      <el-input
        v-model="input"
        style="width: 240px"
        placeholder="请输入任务名称"
      />

      <el-button type="primary" style="margin-left: 5px" @click="submitHandle"
        >提交</el-button
      >
    </div>

    <el-radio-group v-model="status" size="large" @change="changeHandle">
      <el-radio-button label="全部" :value="2" />
      <el-radio-button label="已完成" :value="1" />
      <el-radio-button label="未完成" :value="0" />
    </el-radio-group>

    <el-table :data="showTodoList" border style="width: 100%">
      <el-table-column fixed prop="sign" label="#">
        <template #default="scope">
          <el-checkbox
            v-model="scope.row.isComplete"
            @change="signComplete(scope.row)"
          />
          <!-- <el-button link type="primary" size="small">Edit</el-button> -->
        </template>
      </el-table-column>
      <el-table-column fixed prop="todoName" label="任务描述" />
      <el-table-column prop="createTime" label="创建时间" width="150" />
      <el-table-column prop="completeTime" label="完成时间" width="150" />
      <el-table-column prop="taskStatus" label="是否完成" width="120">
        <template #default="scope">
          {{ getTaskStatus(scope.row.taskStatus) }}
        </template>
      </el-table-column>
      <el-table-column fixed="right" label="操作" width="120">
        <template #default="scope">
          <el-button
            link
            type="primary"
            size="small"
            @click="deleteHandle(scope.row)"
          >
            删除
          </el-button>
          <!-- <el-button link type="primary" size="small">Edit</el-button> -->
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script lang="ts" setup>
import { ElMessage } from "element-plus";
import { ref, reactive, computed } from "vue";
import { timeFormat } from "@/util/index";
const input = ref("");
const todoList = ref([]);
const status = ref(2);
const showTodoList = ref([]);
function init() {
  const todoLocalStorage = localStorage.getItem("todoList")
    ? JSON.parse(localStorage.getItem("todoList"))
    : [];
  todoList.value.push(...todoLocalStorage);

  // 全部
  setShowTodoList();
}

init();

// 单选框change
function changeHandle() {
  setShowTodoList();
}

// 设置显示的todolist
function setShowTodoList() {
  showTodoList.value = [];
  if (status.value === 2) {
    showTodoList.value.push(...todoList.value);
  } else if (status.value === 1) {
    const ftTodoList = todoList.value.filter((todo) => {
      return todo.isComplete;
    });
    showTodoList.value.push(...ftTodoList);
  } else if (status.value === 0) {
    const ftTodoList = todoList.value.filter((todo) => {
      return !todo.isComplete;
    });
    showTodoList.value.push(...ftTodoList);
  }
}

// 进行提交
function submitHandle() {
  const inpVal = input.value;
  if (!inpVal) {
    ElMessage({
      message: "文本框值不能为空",
      type: "error",
    });
    return;
  }
  createToList(inpVal);
  input.value = "";
}

// 创建一条任务清单
function createToList(todoName) {
  const todoIndex = todoList.value.findIndex((to) => {
    return to.todoName === todoName;
  });

  if (todoIndex !== -1) {
    ElMessage({
      message: "添加任务失败,该任务已存在",
      type: "error",
    });
    return;
  }

  todoList.value.push({
    todoName: todoName,
    createTime: timeFormat(new Date()),
    completeTime: null,
    isComplete: false,
    taskStatus: 0,
  });
  setShowTodoList();
  setStorage(todoList.value);
}

function deleteHandle(row) {
  const index = todoList.value.findIndex((to) => {
    return to.todoName === row.todoName;
  });
  const showIndex = showTodoList.value.findIndex((to) => {
    return to.todoName === row.todoName;
  });
  showTodoList.value.splice(showIndex, 1);
  todoList.value.splice(index, 1);
  setStorage(todoList.value);
}

// 标记完成
function signComplete(row) {
  const index = todoList.value.findIndex((to) => {
    return to.todoName === row.todoName;
  });
  todoList.value[index].taskStatus = todoList.value[index].isComplete ? 1 : 0;
  todoList.value[index].completeTime = timeFormat(new Date());

  setStorage(todoList.value);
  setShowTodoList();
}

// 获取任务的状态
function getTaskStatus(val) {
  let str = "";
  switch (val) {
    case 0:
      str = "未完成";
      break;
    case 1:
      str = "已完成";
      break;
  }
  return str;
}

function setStorage(todoList) {
  localStorage.setItem("todoList", JSON.stringify(todoList));
}
</script>

<style lang="scss" scoped>
.op-container {
  margin-bottom: 10px;
}
.todo-list-container {
  max-width: 800px;
  margin: 0 auto;
}

.filters {
  margin: 0;
  padding: 0;
  list-style: none;

  li {
    display: inline;
    a {
      color: inherit;
      margin: 3px;
      padding: 3px 7px;
      text-decoration: none;
      border: 1px solid transparent;
      border-radius: 3px;
      &:hover {
        border-color: rgba(175, 47, 47, 0.1);
      }

      &.selected {
        border-color: rgba(175, 47, 47, 0.2);
      }
    }
  }
}
</style>

这边的代码我是这么写的,当时大脑不是很清晰,代码还有可优化的地方,我再提供一个优化后的代码

下面的这段代码加上了一些ts的代码进行了约束

<template>
  <div class="todo-list-container">
    <div class="op-container">
      <el-input
        v-model="input"
        style="width: 240px"
        placeholder="请输入任务名称"
      />

      <el-button type="primary" style="margin-left: 5px" @click="addTodoHandle"
        >提交</el-button
      >
    </div>

    <el-radio-group v-model="filterStatus" size="large" @change="changeHandle">
      <el-radio-button label="全部" :value="2" />
      <el-radio-button label="已完成" :value="1" />
      <el-radio-button label="未完成" :value="0" />
    </el-radio-group>

    <el-table :data="showTodoList" border style="width: 100%">
      <el-table-column fixed prop="sign" label="#">
        <template #default="scope">
          <el-checkbox
            v-model="scope.row.isComplete"
            @change="signTodoComplete(scope.row.id)"
          />
        </template>
      </el-table-column>
      <el-table-column fixed prop="todoName" label="任务名称" />
      <el-table-column prop="createTime" label="创建时间" width="150" />
      <el-table-column prop="completeTime" label="完成时间" width="150" />
      <el-table-column prop="showTaskStatus" label="是否完成" width="120" />
      <el-table-column fixed="right" label="操作" width="120">
        <template #default="scope">
          <el-button
            link
            type="primary"
            size="small"
            @click="deleteTodo(scope.row)"
          >
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script lang="ts" setup>
import { ElMessage } from "element-plus";
import { ref, reactive, computed } from "vue";
import { timeFormat, generateId } from "@/util/index";

enum TaskStatus {
  no = 0, //未完成
  yes = 1, //完成
}

interface Todo {
  id: number;
  todoName: string;
  createTime: string;
  completeTime: string | null;
  taskStatus: TaskStatus;
}

const input = ref(""); //总任务列表
const todoList: Todo[] = []; //总任务列表
const todoListRef = ref(todoList);
const filterStatus = ref(2); //给个默认值,默认显示全部

init();
/**
 * 初始化会去从缓存里面读取值
 */
function init() {
  const todoLocalStorage = localStorage.getItem("todoList");
  const todoList = todoLocalStorage ? JSON.parse(todoLocalStorage) : [];
  todoListRef.value.push(...todoList);
}

// 添加一个任务处理函数
function addTodoHandle() {
  if (!input.value) {
    ElMessage({
      showClose: true,
      message: "任务名称不能为空!!",
      type: "error",
    });
    return;
  }

  // 创建任务
  createTodo(input.value);

  // 清空文本框的值
  input.value = "";
}

//当前显示的todolist
const showTodoList = computed(() => {
  const newTodoList = [];
  // 显示全部
  if (filterStatus.value === 2) {
    newTodoList.push(...todoListRef.value);
  }
  // 其他两个显示
  else {
    const ftTodoList = todoListRef.value.filter((todo) => {
      return todo.taskStatus === filterStatus.value;
    });

    newTodoList.push(...ftTodoList);
  }

  const showTodoList = newTodoList.map((todo) => {
    const newTodo = {
      ...todo,
      showTaskStatus: getShowTaskStatus(todo.taskStatus),
      isComplete: todo.taskStatus === TaskStatus.yes ? true : false,
    };
    return newTodo;
  });

  return showTodoList;
});

/**
 * 创建一个任务
 */
function createTodo(todoName: string) {
  // 任务对象
  const todoObj: Todo = {
    id: generateId(),
    todoName,
    createTime: timeFormat(new Date()),
    completeTime: null,
    taskStatus: TaskStatus.no,
  };

  todoListRef.value.push(todoObj);

  // 记录到缓存
  setStorage(todoListRef.value);
}

/**
 * 删除一个任务
 */
function deleteTodo(id: number) {
  const index = todoListRef.value.findIndex((todo) => {
    return todo.id === id;
  });
  todoListRef.value.splice(index, 1);

  // 记录到缓存
  setStorage(todoListRef.value);
}

/**
 * 给某个任务标记完成
 */
function signTodoComplete(id: number) {
  const index = todoListRef.value.findIndex((todo) => {
    return todo.id === id;
  });

  // 完成和未完成的切换
  todoListRef.value[index].taskStatus =
    todoListRef.value[index].taskStatus === TaskStatus.no
      ? TaskStatus.yes
      : TaskStatus.no;

  // 缓存记录
  setStorage(todoListRef.value);
}

/**
 * 拿到任务状态的中文信息
 */
function getShowTaskStatus(val: number) {
  let str = "";
  switch (val) {
    case 0:
      str = "未完成";
      break;
    case 1:
      str = "已完成";
      break;
  }
  return str;
}

function setStorage(todoList: Todo[]) {
  localStorage.setItem("todoList", JSON.stringify(todoList));
}
</script>

<style lang="scss" scoped>
.op-container {
  margin-bottom: 10px;
}
.todo-list-container {
  max-width: 800px;
  margin: 0 auto;
}

.filters {
  margin: 0;
  padding: 0;
  list-style: none;

  li {
    display: inline;
    a {
      color: inherit;
      margin: 3px;
      padding: 3px 7px;
      text-decoration: none;
      border: 1px solid transparent;
      border-radius: 3px;
      &:hover {
        border-color: rgba(175, 47, 47, 0.1);
      }

      &.selected {
        border-color: rgba(175, 47, 47, 0.2);
      }
    }
  }
}
</style>

效果预览

在这里插入图片描述

最后回复

在这里插入图片描述

结语

我觉得一个前端开发者来说,熟悉底层熟悉原理是最重要的事情,知道了原理,知道了哪些工具是用来干什么的,解决什么样的问题的,大局观比较重要,至于ui框架,一些js库都是顺带学习的事情,那些ui,js框架等等不都是基于原生的吗,能够解决问题的人不才是公司所需要的吗?我是一个热爱it的存粹的技术开发,就算一时找不到工作也无法让我气馁,只会越挫越勇把,加油,就算it这行走不通,也不影响我对它的兴趣和热情。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值