Starting again company 03

1.vue单向数据流

1.1单向数据流核心

确保数据在组件间传递是单向的,从父组件流向子组件。vue中的单向数据流主要通过props实现,Vue2 的单向数据流核心是 "props 只读,修改需通过事件通知父组件"。

1.2单向数据流存在的意义

数据流向清晰:所有数据变更都能追溯到源头(通常是父组件或更上层的状态管理),便于调试和维护。

避免数据混乱:若允许子组件直接修改父组件数据,当多个子组件同时修改时,会导致数据状态不可预测。

1.3具体实现展示
1.3.1父传子单向数据流

父组件属性绑定传入数据

javascript 复制代码
<!-- 父组件 Parent.vue -->
<template>
  <Child :message="parentMsg" />
</template>
<script>
import Child from './Child.vue'
export default {
  components: { Child },
  data() {
    return { parentMsg: 'Hello from parent' }
  }
}
</script>

子组件props接收数据并使用

javascript 复制代码
<!-- 子组件 Child.vue -->
<template>
  <div>{{ message }}</div> <!-- 显示父组件传递的数据 -->
</template>
<script>
export default {
  props: ['message'] // 声明接收的 props
}
</script>
1.3.2子组件修改数据:通过事件通知父组件

子组件通过 $emit 触发一个自定义事件,并传递需要修改的值

javascript 复制代码
<!-- 子组件 Child.vue -->
<template>
  <button @click="changeMsg">修改数据</button>
</template>
<script>
export default {
  props: ['message'],
  methods: {
    changeMsg() {
      // 触发自定义事件,传递新值
      this.$emit('update-message', 'New message from child')
    }
  }
}
</script>

父组件监听该事件,在事件处理函数中修改自身数据,通过 props 自动同步到子组件。

javascript 复制代码
<!-- 父组件 Parent.vue -->
<template>
  <!-- 监听子组件的自定义事件,执行修改逻辑 -->
  <Child :message="parentMsg" @update-message="handleUpdate" />
</template>
<script>
export default {
  data() { return { parentMsg: 'Hello' } },
  methods: {
    handleUpdate(newVal) {
      this.parentMsg = newVal // 父组件自行修改数据
    }
  }
}
</script>

2.vue2项目打包发布后项目刷新无变化

主要原因是打包后静态资源文件名未变,服务器返回304缓存,需通过「文件名加哈希」让更新后的资源文件名不同,确保 JS、CSS、图片等资源通过「哈希值」区分版本。

强制刷新浏览器 ,排除本地缓存--->检查 dist 目录是否更新 ,服务器文件是否为最新--->配置 vue.config.js 确保 JS/CSS 带哈希- -->服务器配置 index.html 不缓存,静态资源长缓存;

2.1JS配置 webpack.config.js 的 output
javascript 复制代码
const path = require('path');

module.exports = {
  output: {
    // 入口 JS 文件(如 main.js)的输出路径和命名
    filename: 'js/[name].[contenthash:8].js', 
    // 异步加载的 chunk(如路由懒加载的组件)的命名
    chunkFilename: 'js/[name].[contenthash:8].chunk.js', 
    // 输出目录(通常为 dist)
    path: path.resolve(__dirname, 'dist'),
    // 每次打包前清空 dist 目录(避免旧文件残留)
    clean: true 
  }
};
2.2CSS 提取带内容哈希

如果用 mini-css-extract-plugin 提取 CSS 为单独文件,需同步配置 CSS 的文件名.

javascript 复制代码
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'] // 提取 CSS 到文件
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      // CSS 文件命名(同样使用 contenthash)
      filename: 'css/[name].[contenthash:8].css',
      chunkFilename: 'css/[name].[contenthash:8].chunk.css'
    })
  ]
};
2.3确保 HTML 不缓存

即使 JS/CSS 带哈希,若 index.html 被缓存,浏览器仍会加载旧 HTML 中引用的旧资源路径

javascript 复制代码
server {
  location / {
    root /path/to/your/dist; # 指向打包后的 dist 目录
    try_files $uri $uri/ /index.html; # 支持 Vue 路由 history 模式
    # 对 HTML 禁用缓存
    add_header Cache-Control "no-cache, no-store, must-revalidate";
    add_header Pragma "no-cache"; # 兼容 HTTP/1.0
    add_header Expires "0"; # 过期时间设为 0
  }

  # 带哈希的静态资源可长期缓存(1年)
  location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|eot|ttf)$ {
    add_header Cache-Control "max-age=31536000, immutable";
  }
}

3.CDN(内容分发网络)

核心目标通过分布式节点网络,将静态资源缓存到离用户最近的节点,从而降低延迟,提升访问速度,并减轻服务器的压力。

3.1核心架构
  1. 源站(Origin Server)

    • 存放原始资源的服务器(即你的业务服务器,如部署前端代码的 Nginx 服务器)。

    • CDN 节点会定期从源站同步资源(首次请求未命中时也会主动拉取)。

  2. CDN 节点(Edge Node)

    • 分布在全球 / 全国各地区的缓存服务器(如一线城市、二三线城市、海外地区),直接向用户提供资源。

    • 节点数量越多、覆盖越广,用户访问延迟越低(例如北京用户从北京节点获取资源,无需访问千里之外的源站)。

  3. 中心控制系统(DNS + 调度系统)

    • DNS 解析:通过自定义 DNS 服务器,将用户的域名解析到「最优 CDN 节点」(而非源站 IP)。

    • 调度策略:根据用户 IP 地理位置、节点负载、网络质量等,选择延迟最低的节点(例如上海用户优先分配到上海节点)。

3.2 CDN的完整工作流程
  1. 用户发起请求 :用户在浏览器输入 https://cdn.example.com/index.html,请求访问前端页面。

  2. DNS 解析导向 CDN 节点:

    • 本地 DNS 向 CDN 的 DNS 服务器查询 cdn.example.com 的 IP。

    • CDN DNS 根据用户 IP 定位到最近的节点(如杭州节点),返回该节点 IP。

  3. CDN 节点处理请求:

    用户向杭州节点请求 index.html,节点检查本地缓存:

    • 若已缓存且有效,直接返回缓存的 index.html。

    • 若未缓存或已过期,节点向源站(如 origin.example.com)请求 index.html,缓存后返回给用户。

  4. 加载关联资源 :index.html 中引用的 app.456.js style.789.css 等资源,同样通过上述流程从 CDN 节点获取(若命中缓存,加载速度极快)。

  5. 资源更新与同步 :当前端代码更新并重新打包后(如 app.678.js),由于文件名哈希变化,CDN 节点会将其视为新资源,自动从源站拉取并缓存,用户下次访问时即可获取最新版本。

4.const声明对象是否能被修改

const声明的对象能被修改 ,与js的堆内存的存储机制有关。

  • 基本类型的值存储在栈内存中,变量指向的是具体的值。
  • 引用类型的值是存储在堆内存 中,变量在栈内存中存储的是指向堆内存中该对象的引用地址(类似指针)。

基本类型(值直接存储在栈内存中,变量与值直接绑定)

javascript 复制代码
const num = 10;
num = 20; // 报错:Assignment to constant variable(不能给常量重新赋值)

const str = 'hello';
str = 'world'; // 同样报错

const bool = true;
bool = false; // 报错

引用类型(堆内存指向引用地址,类似指针)

javascript 复制代码
const obj = { name: 'foo' };
obj = { age: 18 }; // 报错:堆内存中创建新对象引用地址发生改变
obj.name = 'bar'; // 允许,修改属性值
obj.age = 18;     // 允许,新增属性
delete obj.name;  // 允许,删除属性

const 与堆内存的联系在于 ------ 它保护的是栈内存中指向堆内存的引用地址不变,但不限制堆内存中对象本身的修改。

5.EventBus(全局事件总线)

适合解决非父子组件间的通信问题,核心思路通过全局的Vue实例作为"事件总线"实现事件的发布于订阅。

5.1.创建EventBus实例

创建独立的事件总线文件,作为全局的 "中介",管理所有组件的事件订阅与发布。

javascript 复制代码
// src/utils/eventBus.js
import Vue from 'vue'
// 实例化一个Vue对象作为事件总线
export default new Vue()
5.2$on订阅事件--接收数据

接收数据的组件中,通过 $on 订阅事件,并在组件销毁前用 $off 取消订阅(避免内存泄漏)。

javascript 复制代码
<!-- 组件A:src/components/ComponentA.vue -->
<template>
  <div>
    <h3>组件A(接收方)</h3>
    <p>收到的消息:{{ receivedMsg }}</p>
  </div>
</template>

<script>
import bus from '@/utils/eventBus' // 导入事件总线

export default {
  data() {
    return {
      receivedMsg: ''
    }
  },
  mounted() {
    // 订阅名为 "sendToA" 的事件,回调函数接收参数
    bus.$on('sendToA', (msg) => {
      this.receivedMsg = msg // 处理收到的数据
    })
  },
  beforeDestroy() {
    // 组件销毁前取消订阅,防止事件重复触发
    bus.$off('sendToA')
  }
}
</script>
5.3$emit发布事件--传递数据
javascript 复制代码
<!-- 组件B:src/components/ComponentB.vue -->
<template>
  <div>
    <h3>组件B(发送方)</h3>
    <button @click="sendMessage">向组件A发送消息</button>
  </div>
</template>

<script>
import bus from '@/utils/eventBus' // 导入事件总线

export default {
  methods: {
    sendMessage() {
      // 发布名为 "sendToA" 的事件,并传递数据
      bus.$emit('sendToA', '你好,组件A!我是组件B~')
    }
  }
}
</script>

5.UniApp中分包

通过将代码拆分为主包和多个分包,实现按需加载,提升应用性能。

5.1分包概念
  1. 主包:包含启动页、TabBar 页面及所有分包都需用到的公共资源(如全局组件、工具类),是应用首次启动时必须加载的部分。

  2. 分包:按功能模块拆分的代码包,只有当用户访问分包内的页面时,才会触发下载(H5 端除外,H5 会打包为单独 chunk,按需加载)。

  3. 限制:

    • 微信小程序:主包 + 所有分包大小不超过 20MB,单个分包不超过 2MB(最新限制可能放宽,以官方文档为准)。

    • 其他平台(如 App、支付宝小程序等)也有各自的大小限制,需参考对应平台规范。

5.2分包配置方法

项目根目录的 pages.json 中配置 subPackages(或 subpackages,大小写不敏感)

javascript 复制代码
{
  "pages": [
    // 主包页面(必须放在 pages 数组中)
    {
      "path": "pages/index/index",
      "style": { ... }
    },
    {
      "path": "pages/login/login",
      "style": { ... }
    }
  ],
  "subPackages": [
    // 分包 1:用户模块
    {
      "root": "pages/user", // 分包根目录(需手动创建文件夹)
      "pages": [
        {
          "path": "profile/profile", // 页面路径,完整路径为 pages/user/profile/profile
          "style": { ... }
        },
        {
          "path": "settings/settings", // 完整路径:pages/user/settings/settings
          "style": { ... }
        }
      ]
    },
    // 分包 2:商品模块
    {
      "root": "pages/goods",
      "pages": [
        {
          "path": "list/list",
          "style": { ... }
        }
      ]
    }
  ]
}
5.3分包预加载与页面跳转

页面跳转:分包内页面的跳转路径需使用完整路径(包含分包根目录)。

javascript 复制代码
// 从主包跳转到分包页面
uni.navigateTo({
  url: '/pages/user/profile/profile'
});

// 分包内页面互跳(也需完整路径)
uni.navigateTo({
  url: '/pages/goods/list/list'
});

分包预加载 :配置分包在特定时机预加载(进入主包某页面),在 pages.json 中添加 preloadRule。

javascript 复制代码
{
  "preloadRule": {
    // 当进入主包的 index 页面时,预加载 user 分包
    "pages/index/index": {
      "network": "all", // 网络环境:all(不限)/ wifi(仅wifi)
      "packages": ["pages/user"] // 需预加载的分包 root 列表
    },
    // 当进入 goods/list 页面时,预加载其他分包
    "pages/goods/list/list": {
      "network": "wifi",
      "packages": ["pages/order"]
    }
  }
}

6.其他的一些面试问题前期有面过

6.1生命周期,promise,事件循环(同步任务,微任务),canvas,输入地址流程,页面渲染流程,git提交代码,markdown样式调整,响应原理,数据更改后未渲染,created与mounted操作dom节点,echarts图表的实际运用。
相关推荐
无限聚核8 分钟前
抖音 certificate.prepare 之后怎么验券?和美团 msconsume 差在哪,无限聚核
前端·微信小程序
2603_9658966217 分钟前
Grid 网格布局|CSS 二维页面排版体系
前端·css
有味道的男人33 分钟前
搜好货平台关键词商品搜索接口:分页容错与商品数据轻量化提取方案
服务器·前端·javascript
lovingsoft1 小时前
Chrome Lighthouse 详解
前端·chrome
Qlly1 小时前
全栈工程师怎么接需求?从一句「加个功能」聊到能开发、能验收
前端·后端
马可家的菠萝1 小时前
你的微信“文件传输助手”,是不是已经成了第二个网盘?
前端·后端·架构
略略略啦1 小时前
Vibe Coding 基于Spec DD和TDD的实践指南
前端
shmily麻瓜小菜鸡2 小时前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式
打工仔折腾 AI2 小时前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战
汉堡大王95272 小时前
单次输出拉到100万Token:拆完 Gemini 4 Argon 的续写协议,才看懂谷歌这7个月在憋什么
前端·人工智能·后端