当前位置: 首页 > news >正文

前端小食堂 | Day13 - Vue.js 进阶烹饪术

🚀 今日主菜:高效开发の秘密武器

1. 动态组件の七十二变
<template>  
  <!-- 🎭 魔法变形术 -->  
  <component  
    :is="currentComponent"  
    :key="componentKey"  
    class="animated-component"  
  />  

  <!-- 控制按钮 -->  
  <button @click="toggleComponent">  
    切换形态 🔄  
  </button>  
</template>  

<script setup>  
import { shallowRef } from 'vue';  
const components = [ComponentA, ComponentB, ComponentC];  
const currentIndex = ref(0);  
const componentKey = ref(0);  

// 强制刷新组件  
const toggleComponent = () => {  
  currentIndex.value = (currentIndex.value + 1) % components.length;  
  componentKey.value++; // 通过改变key强制重渲染  
};  

const currentComponent = shallowRef(components[0]);  
</script>  

<style>  
.animated-component {  
  transition: opacity 0.3s;  
}  
</style>  

🔔 核心技巧

  • 使用 shallowRef 避免不必要的深度响应
  • 通过改变 key 强制组件重置状态
  • 搭配 CSS 过渡实现平滑切换

2. 指令の魔法卷轴
// 📜 点击外部关闭指令  
const clickOutside = {  
  mounted(el, { value: callback }) {  
    el._clickHandler = e => {  
      if (!el.contains(e.target)) callback();  
    };  
    document.addEventListener('click', el._clickHandler);  
  },  
  unmounted(el) {  
    document.removeEventListener('click', el._clickHandler);  
  }  
};  

// 使用示例  
<div v-click-outside="closeMenu">...</div>  

// 🎨 元素跟随指令  
const followCursor = {  
  updated(el, { value: enable }) {  
    if (enable) {  
      document.addEventListener('mousemove', el._follow = (e) => {  
        el.style.transform = `translate(${e.clientX}px, ${e.clientY}px)`;  
      });  
    } else {  
      document.removeEventListener('mousemove', el._follow);  
    }  
  }  
};  

3. 组合式APIの炼金术
// 🧪 智能搜索逻辑复用  
export function useSearch(fetcher: (keyword: string) => Promise<Item[]>) {  
  const keyword = ref('');  
  const results = ref<Item[]>([]);  
  const loading = ref(false);  

  watchDebounced(keyword, async (val) => {  
    if (!val.trim()) return;  
    loading.value = true;  
    try {  
      results.value = await fetcher(val);  
    } finally {  
      loading.value = false;  
    }  
  }, { debounce: 300 });  

  return { keyword, results, loading };  
}  

// 使用示例  
const { keyword, results, loading } = useSearch(async (kw) => {  
  const { data } = await axios.get('/api/search', { params: { q: kw } });  
  return data.items;  
});  

❄️ 冷知识:TypeScript 类型魔法

// 🛡️ 安全的 provide/inject  
import type { InjectionKey } from 'vue';  

interface ThemeConfig {  
  primaryColor: string;  
  darkMode: boolean;  
}  

const themeKey = Symbol() as InjectionKey<ThemeConfig>;  

// 提供端  
provide(themeKey, {  
  primaryColor: '#1890ff',  
  darkMode: false  
});  

// 注入端  
const theme = inject(themeKey, {  
  primaryColor: '默认颜色',  
  darkMode: false  
});  

🌟 实验室黑科技

实现动态主题切换器

<template>  
  <div :style="themeStyle">  
    <button @click="toggleTheme">  
      {{ isDark ? '☀️ 光明' : '🌙 黑暗' }}  
    </button>  
    <slot />  
  </div>  
</template>  

<script setup lang="ts">  
import { computed, reactive } from 'vue';  

const state = reactive({  
  isDark: false,  
  colors: {  
    light: { bg: '#fff', text: '#333' },  
    dark: { bg: '#1a1a1a', text: '#eee' }  
  }  
});  

const themeStyle = computed(() => ({  
  backgroundColor: state.colors[state.isDark ? 'dark' : 'light'].bg,  
  color: state.colors[state.isDark ? 'dark' : 'light'].text,  
  transition: 'all 0.3s ease'  
}));  

const toggleTheme = () => {  
  state.isDark = !state.isDark;  
};  

// 暴露切换方法给其他组件  
defineExpose({ toggleTheme });  
</script>  

明日秘技:《Vue 3 性能调优の火焰掌——内存泄漏排查指南》 🔥
(留言告诉我你遇到的组件复用难题,本魔法导师为你定制解决方案!🔮)


🛎️ 本日避坑指南

  1. 内存泄漏三大元凶
// 🚨 未清理的定时器  
const timer = setInterval(() => {}, 1000);  
onUnmounted(() => clearInterval(timer));  

// 🚨 未解绑的事件监听  
window.addEventListener('resize', handleResize);  
onUnmounted(() => window.removeEventListener('resize', handleResize));  

// 🚨 未释放的第三方库实例  
const editor = new RichEditor();  
onUnmounted(() => editor.destroy());  
  1. 性能陷阱检测表
- [ ] 是否在v-for中使用复杂计算属性  
- [ ] 是否频繁修改大数组的引用  
- [ ] 是否在不需要响应性的地方使用reactive  
- [ ] 是否合理使用v-show替代v-if  
  1. 调试神器
// 追踪组件更新原因  
import { onRenderTracked, onRenderTriggered } from 'vue';  

onRenderTracked((e) => {  
  console.log('追踪依赖:', e);  
});  

onRenderTriggered((e) => {  
  console.log('触发更新:', e);  
});  

相关文章:

  • RISC-V特权模式与寄存器
  • 计网面试准备
  • Vue的生命周期
  • Ubuntu 下 nginx-1.24.0 源码分析 - ngx_conf_param
  • FreeRTOS(7)队列集
  • Redis 主从复制详解:实现高可用与数据备份
  • 【MySQL - 表的内外连接】
  • 【13】单片机编程核心技巧:乘法运算
  • 《Python全栈开发》第2课:HTML骨架搭建 - 从零编写个人简历页面
  • 数字IC后端设计实现教程 |Innovus ICC2 Routing Pin Access Setting设置方法
  • 第十五届蓝桥杯大学B组(握手问题、小球反弹、好数)
  • ChatGPT课件分享(37页PPT)
  • 【亲测有效】Mac系统升级或降级Node.js版本,Mac系统调整node.js版本
  • 【3D视觉学习笔记1】针孔相机模型与坐标系变换
  • 【Azure 架构师学习笔记】- Azure Databricks (17) --Delta Live Table和Delta Table
  • 面试之《webpack从输入到输出经历了什么》
  • 基础网络安全-K8S 配置Ingress-controller 通过HTTPS处理服务请求
  • GB8599-2023标准测试包/小规格测试包/标准生物测试包1.5kg/满负载织物7.5kg/不锈钢金属测试包/空腔负载试验的过程挑战装置(PCD)
  • Linux网络编程之——网络初认识
  • 启智畅想的集装箱号码识别技术,效率与技术的完美结合
  • 教育部、国家发改委联合启动实施教师教育能力提升工程
  • 绍兴柯桥:用一块布托起中国制造的新经纬
  • 江苏省泰州市委常委、宣传部部长刘霞接受审查调查
  • 潘功胜:将下调个人住房公积金贷款利率0.25个百分点
  • 北美票房|“雷霆”开画票房比“美队4”低,但各方都能接受
  • 宋涛就许历农逝世向其家属致唁电