蔚来前端实习一面

78 阅读7分钟

蔚来 一面

flex=1

flex: 1 是 CSS Flexbox 布局中的一个简写属性,它表示一个元素将占据其父容器中所有可用的空间。具体来说,flex: 1flex-grow: 1, flex-shrink: 1, 和 flex-basis: 0 的简写形式。下面是对这三个属性的解释:

  1. flex-grow:定义项目的放大比例,即如果存在剩余空间,该元素将如何占据这些剩余空间。flex-grow: 1 表示该元素将占据所有可用空间。
  2. flex-shrink:定义项目的缩小比例,即如果空间不足,该元素将如何缩小。flex-shrink: 1 表示该元素可以缩小以适应容器的空间。
  3. flex-basis:定义在分配多余空间之前,元素的默认大小。flex-basis: 0 表示元素将完全依赖 flex-grow 来分配空间,而不是使用它的内容大小。

综合起来,flex: 1 的含义是,该元素将尝试占据容器中所有可用的空间,且在空间不足时会按比例缩小。

示例

假设有一个父容器,里面有三个子元素,所有子元素都设置了 flex: 1。这意味着它们将均匀地分配父容器中的所有可用空间。

html复制代码<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flex 1 Example</title>
    <style>
        .container {
            display: flex;
            width: 100%;
            height: 100vh;
        }
        .item {
            flex: 1;
            padding: 10px;
            margin: 5px;
            background-color: lightblue;
            border: 1px solid blue;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="item">Item 1</div>
        <div class="item">Item 2</div>
        <div class="item">Item 3</div>
    </div>
</body>
</html>

如何保证前端获取到实时的数据

1. 轮询(Polling)

轮询是一种简单但有效的方法,前端通过定期发送请求来检查服务器上的数据是否有更新。

实现方式:

 function fetchData() {
    fetch('/api/data')
        .then(response => response.json())
        .then(data => {
            // 处理数据
            console.log(data);
        })
        .catch(error => console.error('Error:', error));
}
​
// 每隔5秒钟请求一次数据
setInterval(fetchData, 5000);
  1. 长轮询(Long Polling)

长轮询是一种改进的轮询方法,服务器在数据没有更新时保持请求挂起,直到有新数据或请求超时才返回结果。

实现方式:

function longPolling() {
    fetch('/api/data')
        .then(response => response.json())
        .then(data => {
            // 处理数据
            console.log(data);
            // 继续长轮询
            longPolling();
        })
        .catch(error => {
            console.error('Error:', error);
            // 出错后稍等片刻再重试
            setTimeout(longPolling, 5000);
        });
}
​
// 启动长轮询
longPolling();

3. WebSocket

WebSocket 提供了在单个 TCP 连接上进行全双工通信的功能,适合实时性要求高的场景。

服务器端实现(Node.js):

 const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });
​
server.on('connection', ws => {
    ws.on('message', message => {
        console.log(`Received message => ${message}`);
    });
​
    // 发送实时数据
    setInterval(() => {
        ws.send(JSON.stringify({ data: 'real-time data' }));
    }, 1000);
});

前端实现:

const socket = new WebSocket('ws://localhost:8080');socket.onopen = function(event) {
    console.log('WebSocket is connected.');
};socket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    console.log('Received:', data);
};socket.onclose = function(event) {
    console.log('WebSocket is closed.');
};socket.onerror = function(error) {
    console.log('WebSocket error:', error);
};

4. Server-Sent Events (SSE)

SSE 允许服务器向浏览器推送实时更新,适合单向数据流的实时更新场景。

服务器端实现(Node.js):

 const http = require('http');
​
http.createServer((req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });
​
    // 发送实时数据
    setInterval(() => {
        res.write(`data: ${JSON.stringify({ data: 'real-time data' })}\n\n`);
    }, 1000);
}).listen(8080);

前端实现:

 const eventSource = new EventSource('/api/data');eventSource.onmessage = function(event) {
    const data = JSON.parse(event.data);
    console.log('Received:', data);
};eventSource.onerror = function(error) {
    console.error('EventSource failed:', error);
};

5. GraphQL Subscriptions

GraphQL Subscriptions 允许你订阅某些事件,当这些事件发生时,服务器会推送更新给客户端。

服务器端实现(使用 Apollo Server):

 const { ApolloServer, gql, PubSub } = require('apollo-server');
const pubsub = new PubSub();
​
const typeDefs = gql`
    type Query {
        hello: String
    }
    type Subscription {
        message: String
    }
`;
​
const resolvers = {
    Query: {
        hello: () => 'Hello world!'
    },
    Subscription: {
        message: {
            subscribe: () => pubsub.asyncIterator(['MESSAGE'])
        }
    }
};
​
const server = new ApolloServer({ typeDefs, resolvers });
​
server.listen().then(({ url }) => {
    console.log(`🚀 Server ready at ${url}`);
    setInterval(() => {
        pubsub.publish('MESSAGE', { message: 'Hello!' });
    }, 1000);
});

前端实现(使用 Apollo Client):

 import { ApolloClient, InMemoryCache, HttpLink, split } from '@apollo/client';
import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities';
import { gql } from 'apollo-boost';
​
const httpLink = new HttpLink({
    uri: 'http://localhost:4000/graphql'
});
​
const wsLink = new WebSocketLink({
    uri: `ws://localhost:4000/graphql`,
    options: {
        reconnect: true
    }
});
​
const link = split(
    ({ query }) => {
        const definition = getMainDefinition(query);
        return (
            definition.kind === 'OperationDefinition' &&
            definition.operation === 'subscription'
        );
    },
    wsLink,
    httpLink
);
​
const client = new ApolloClient({
    link,
    cache: new InMemoryCache()
});
​
client.subscribe({
    query: gql`
        subscription {
            message
        }
    `
}).subscribe({
    next(data) {
        console.log(data);
    }
});

Vue3比Vue2好在哪里

1. 性能提升

  • 编译器优化:Vue 3 的编译器进行了大幅优化,生成的代码更高效,运行速度更快。
  • 虚拟 DOM 重写:Vue 3 重新实现了虚拟 DOM,提升了渲染性能,尤其是在大型应用和复杂界面中表现更好。
  • 更快的初次渲染和更新:通过优化组件的初始化和更新过程,Vue 3 提供了更快的初次渲染和更新性能。

2. 组合式 API (Composition API)

  • 灵活的代码组织:组合式 API 允许开发者将组件逻辑按功能组织,而不是按组件生命周期钩子分散在多个地方。这使得代码更易读、易维护,尤其是在大型组件中。
  • 可重用性:开发者可以更方便地提取和复用逻辑片段,避免了传统混入(mixins)的局限性和潜在冲突。
 // 示例:使用组合式 API
import { ref, onMounted } from 'vue';
​
export default {
  setup() {
    const count = ref(0);
​
    onMounted(() => {
      console.log('Component mounted');
    });
​
    function increment() {
      count.value++;
    }
​
    return {
      count,
      increment
    };
  }
};

3. 更好的 TypeScript 支持

  • 原生支持 TypeScript:Vue 3 从设计之初就考虑了 TypeScript 的支持,提供了更好的类型推断和类型检查,使得使用 TypeScript 开发 Vue 应用更加顺畅。
  • Vue 3 + TypeScript:类型定义和开发体验得到了显著改进,提供了更强的类型安全和更好的开发工具支持。

4. Fragment, Teleport 和 Suspense

  • Fragment:允许组件返回多个根元素,而不需要包裹在单一根元素中,减少了不必要的 DOM 层级。
  • Teleport:提供了一种方式,可以将组件的 DOM 渲染到指定的 DOM 节点之外,适用于弹出框、模态窗口等场景。
  • Suspense:用于处理异步组件的加载状态,使得处理异步逻辑更加简单和直观。
html复制代码<!-- 示例:使用 Teleport -->
<template>
  <div>
    <button @click="showModal = true">Show Modal</button>
    <teleport to="body">
      <div v-if="showModal" class="modal">
        <p>This is a modal!</p>
        <button @click="showModal = false">Close</button>
      </div>
    </teleport>
  </div>
</template><script>
import { ref } from 'vue';
​
export default {
  setup() {
    const showModal = ref(false);
    return { showModal };
  }
};
</script>

5. 更小的打包体积

  • 树摇优化:Vue 3 的设计使得未使用的特性不会被打包,从而减少了最终的打包体积,提升了加载性能。

6. Improved Custom Directives

  • 自定义指令的改进:Vue 3 中的自定义指令 API 更加简洁和直观,使得创建和使用自定义指令变得更加简单。

7. Composition API 和 Options API 并存

  • 向后兼容:尽管引入了组合式 API,Vue 3 仍然保留了 Options API,保证了与现有 Vue 2 代码库的兼容性,使得迁移过程更加平滑。

8. 更好的响应式系统

  • Proxy-based 响应性:Vue 3 使用 Proxy 代替 Vue 2 中的 Object.defineProperty 实现响应式系统,解决了 Vue 2 中的一些限制,例如无法检测属性的添加或删除。
 // 示例:响应性系统
import { reactive } from 'vue';
​
const state = reactive({
  count: 0
});
​
state.count++; // 响应式更新

9. 提高的开发者体验

  • 更好的调试工具:Vue 3 提供了改进的 Vue DevTools,支持新的组合式 API,并提供了更强大的调试功能。
  • 增强的文档和社区支持:Vue 3 伴随着更好的文档和教程资源,使得开发者能够更快地上手和应用。

v-model

在自定义组件中实现 v-model 绑定需要以下步骤:

  1. 使用 props 接收父组件传入的值。
  2. 在组件内部修改值时,发出更新事件。

v-model 在 Vue 3 中的实现依赖于 props 和事件。通过使用 props 接收父组件传递的值,并在子组件内部修改值时发出相应的事件,从而实现双向绑定。Vue 3 还允许自定义 v-model 绑定属性,支持多个 v-model 绑定,使得组件通信更加灵活和强大。

数据流向

  • props 是单向数据流,数据只能从父组件传递到子组件,子组件不能直接修改 props 的值。
  • v-model 实现双向数据绑定,数据可以在父组件和子组件之间双向流动。

使用场景

  • props 适用于需要从父组件传递数据到子组件且子组件不需要反馈数据给父组件的场景。
  • v-model 适用于需要父组件和子组件之间保持数据同步的场景,特别是表单控件和自定义输入组件。

实现方式

  • props 通过父组件传递数据,子组件通过定义 props 接收数据。
  • v-model 通过 value 属性和 input 事件的结合实现,Vue 3 中使用 modelValueupdate:modelValue 事件的组合。

整数转罗马数字

function intToRoman(num) {
    const val = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
    const syms = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];
    
    let roman = '';
    for (let i = 0; i < val.length; i++) {
        while (num >= val[i]) {
            num -= val[i];
            roman += syms[i];
        }
    }
    return roman;
}
​
// 测试
console.log(intToRoman(3));    // 输出: "III"
console.log(intToRoman(58));   // 输出: "LVIII"
console.log(intToRoman(1994)); // 输出: "MCMXCIV"