<重构>笔记

重构:
在不改变的前提下,提高代码的可理解性,降低其修改成本


The rule of three
添加功能时一并重构
修补错误时一并重构
复审代码时一并重构

composing method

a. Extract method. divide a method into two or more method.
提炼方法, 把能分开,重用的部分单独做一个方法。

b. Inline method. conclude two or method into one method.
和Extract method相反, 概括多个方法成一个, 简化代码.

c. Inline temp. remove temp variable as we can.


d. Replace temp with query. change temp variable 's operation into a method that can be recall some other place


e. Introduce explaining variable. change series of operation into some explaining variable, use clear name


f. Split temporary variable. won't reuse temp variable for many set value operation, it make other confused


g. Remove assignments to parameters.
create a temp variable instead of object, java only use pass by value (参数不要用来赋值, 使用final, 避免对参数赋值)


h. Replace method with method object.
create method object( TestObject _testObject), use 'Extract method', use '_testObject.testMethod()'(method object)


i. Substitute algorithm. improve algorithm




Moving features between objects


a. Move method

b. Move field

c. Extract class.

d. Inline class.

e. Hide delegate. (对method进行加一层封装,使Client不能直接访问method. 简单委托关系)

f. Remove middle man. 和Hide delegate相反, 合理的隐藏程序基于实际系统的变化

g.Introduce foreign method. create new method, set server class entity as argument
ex: Date date = new Date(pro.getYear(), pro.getMonth(), pro.getDay()+1)
----> Date date = nextDay(pro);
staitc Date nextDay(Date pro)
{
return new Date()
}
透传 Attributes​ 此章节假设你已经看过了组件基础。若你还不了解组件是什么,请先阅读该章节。 Attributes 继承​ “透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。 当一个组件以单个元素为根作渲染时,透传的 attribute 会自动被添加到根元素上。举例来说,假如我们有一个 <MyButton> 组件,它的模板长这样: template <!-- <MyButton> 的模板 --> <button>Click Me</button> 一个父组件使用了这个组件,并且传入了 class: template <MyButton class="large" /> 最后渲染出的 DOM 结果是: html <button class="large">Click Me</button> 这里,<MyButton> 并没有将 class 声明为一个它所接受的 prop,所以 class 被视作透传 attribute,自动透传到了 <MyButton> 的根元素上。 对 class 和 style 的合并​ 如果一个子组件的根元素已经有了 class 或 style attribute,它会和从父组件上继承的值合并。如果我们将之前的 <MyButton> 组件的模板改成这样: template <!-- <MyButton> 的模板 --> <button class="btn">Click Me</button> 则最后渲染出的 DOM 结果会变成: html <button class="btn large">Click Me</button> v-on 监听器继承​ 同样的规则也适用于 v-on 事件监听器: template <MyButton @click="onClick" /> click 监听器会被添加到 <MyButton> 的根元素,即那个原生的 <button> 元素之上。当原生的 <button> 被点击,会触发父组件的 onClick 方法。同样的,如果原生 button 元素自身也通过 v-on 绑定了一个事件监听器,则这个监听器和从父组件继承的监听器都会被触发。 深层组件继承​ 有些情况下一个组件会在根节点上渲染另一个组件。例如,我们重构一下 <MyButton>,让它在根节点上渲染 <BaseButton>: template <!-- <MyButton/> 的模板,只是渲染另一个组件 --> <BaseButton /> 此时 <MyButton> 接收的透传 attribute 会直接继续传给 <BaseButton>。 请注意: 透传的 attribute 不会包含 <MyButton> 上声明过的 props 或是针对 emits 声明事件的 v-on 侦听函数,换句话说,声明过的 props 和侦听函数被 <MyButton>“消费”了。 透传的 attribute 若符合声明,也可以作为 props 传入 <BaseButton>。 禁用 Attributes 继承​ 如果你不想要一个组件自动地继承 attribute,你可以在组件选项中设置 inheritAttrs: false。 从 3.3 开始你也可以直接在 <script setup> 中使用 defineOptions: vue <script setup> defineOptions({ inheritAttrs: false }) // ...setup 逻辑 </script> 最常见的需要禁用 attribute 继承的场景就是 attribute 需要应用在根节点以外的其他元素上。通过设置 inheritAttrs 选项为 false,你可以完全控制透传进来的 attribute 被如何使用。 这些透传进来的 attribute 可以在模板的表达式中直接用 $attrs 访问到。 template <span>Fallthrough attribute: {{ $attrs }}</span> 这个 $attrs 对象包含了除组件所声明的 props 和 emits 之外的所有其他 attribute,例如 class,style,v-on 监听器等等。 有几点需要注意: 和 props 有所不同,透传 attributes 在 JavaScript 中保留了它们原始的大小写,所以像 foo-bar 这样的一个 attribute 需要通过 $attrs['foo-bar'] 来访问。 像 @click 这样的一个 v-on 事件监听器将在此对象下被暴露为一个函数 $attrs.onClick。 现在我们要再次使用一下之前小节中的 <MyButton> 组件例子。有时候我们可能为了样式,需要在 <button> 元素外包装一层 <div>: template <div class="btn-wrapper"> <button class="btn">Click Me</button> </div> 我们想要所有像 class 和 v-on 监听器这样的透传 attribute 都应用在内部的 <button> 上而不是外层的 <div> 上。我们可以通过设定 inheritAttrs: false 和使用 v-bind="$attrs" 来实现: template <div class="btn-wrapper"> <button class="btn" v-bind="$attrs">Click Me</button> </div> 小提示:没有参数的 v-bind 会将一个对象的所有属性都作为 attribute 应用到目标元素上。 多根节点的 Attributes 继承​ 和单根节点组件有所不同,有着多个根节点的组件没有自动 attribute 透传行为。如果 $attrs 没有被显式绑定,将会抛出一个运行时警告。 template <CustomLayout id="custom-layout" @click="changeValue" /> 如果 <CustomLayout> 有下面这样的多根节点模板,由于 Vue 不知道要将 attribute 透传到哪里,所以会抛出一个警告。 template <header>...</header> <main>...</main> <footer>...</footer> 如果 $attrs 被显式绑定,则不会有警告: template <header>...</header> <main v-bind="$attrs">...</main> <footer>...</footer> 在 JavaScript 中访问透传 Attributes​ 如果需要,你可以在 <script setup> 中使用 useAttrs() API 来访问一个组件的所有透传 attribute: vue <script setup> import { useAttrs } from 'vue' const attrs = useAttrs() </script> 如果没有使用 <script setup>,attrs 会作为 setup() 上下文对象的一个属性暴露: js export default { setup(props, ctx) { // 透传 attribute 被暴露为 ctx.attrs console.log(ctx.attrs) } } 需要注意的是,虽然这里的 attrs 对象总是反映为最新的透传 attribute,但它并不是响应式的 (考虑到性能因素)。你不能通过侦听器去监听它的变化。如果你需要响应性,可以使用 prop。或者你也可以使用 onUpdated() 使得在每次更新时结合最新的 attrs 执行副作用。 根据以上内容做一份学习笔记,要详细,内容要丰富。要做总结,最好绘制图表方便学习在举几个父子调用的例子
最新发布
09-19
# 学习笔记:Vue 透传 Attributes 详解 ## 1. 核心概念理解 ### 什么是“透传 Attributes”? **透传 attribute** 是指传递给组件但未在 `props` 或 `emits` 中声明的 HTML 属性或事件监听器(如 `class`、`style`、`id`、`@click` 等),这些属性会自动“穿透”到组件内部的根元素上。 > 示例: ```vue <MyButton class="large" @click="onClick" /> ``` 若 `<MyButton>` 未声明 `class` 和 `@click`,它们将被自动应用到其模板的根元素上。 --- ## 2. Attributes 继承机制 ### 单根节点组件的自动继承 当组件只有一个根节点时,所有透传 attribute 自动绑定到该根元素。 #### 案例演示: ```vue <!-- 子组件 MyButton.vue --> <template> <button class="btn">Click Me</button> </template> ``` ```vue <!-- 父组件使用 --> <MyButton class="large" id="submit-btn" @click="handleClick" /> ``` ✅ 渲染结果: ```html <button class="btn large" id="submit-btn">Click Me</button> ``` > 🔍 **说明**:`class` 被合并,`id` 直接继承,`@click` 监听器也附加到 `<button>` 上。 --- ### class 与 style 的合并规则 | 原有值 | 透传值 | 最终结果 | |--------|--------|----------| | `"btn"` | `"large"` | `"btn large"` | | `:class="{ active: true }"` | `class="highlight"` | 合并生效 | 📌 **注意**:Vue 智能合并多个来源的 `class` 和 `style`。 --- ### v-on 监听器继承 - 父级的 `@click` → 子组件根元素 - 子组件自身 `v-on:click` 也会触发 - 多个监听器按顺序执行 ```vue <template> <button @click="innerClick">Inner Button</button> </template> <!-- 父组件调用 --> <MyButton @click="parentClick" /> ``` 🎯 执行顺序:`innerClick` → `parentClick` --- ## 3. 深层组件继承(嵌套场景) 组件可作为“透明管道”,将 attributes 逐层向下传递。 ```vue <!-- MyButton.vue --> <template> <BaseButton /> </template> <!-- BaseButton.vue --> <template> <button>Base</button> </template> ``` ```vue <!-- 父组件 --> <MyButton class="primary" @click="onClick" /> ``` ✅ 结果:`class` 和 `@click` 都透传至 `<BaseButton>` 的 `<button>` 根元素。 > 📌 规则:只有未声明为 `props` 或 `emits` 的属性才会继续透传。 --- ## 4. 禁用 Attributes 继承 ### 使用 `inheritAttrs: false` 适用场景:需要把 attributes 应用到非根元素上。 #### 示例:包装按钮 ```vue <script setup> defineOptions({ inheritAttrs: false }) </script> <template> <div class="btn-wrapper"> <button class="btn" v-bind="$attrs">Click Me</button> </div> </template> ``` ```vue <!-- 调用 --> <MyButton class="large" @click="onClick" /> ``` ✅ 渲染结果: ```html <div class="btn-wrapper"> <button class="btn large" onclick="...">Click Me</button> </div> ``` > ✅ `$attrs` 包含除 props/emits 外的所有 attribute。 --- ## 5. $attrs 对象详解 ### 数据结构示例 ```js // 输入: <MyButton foo-bar="value" @click="onClick" data-test="123" /> // $attrs 内容: { 'foo-bar': 'value', onClick: Function, 'data-test': '123' } ``` 📌 注意事项: - 键名保持原始大小写(如 `'foo-bar'`) - 事件监听器以函数形式暴露(`onClick`) - 不是响应式对象 ❌(不能 watch) --- ## 6. 多根节点组件的行为 多根组件**不支持自动 attribute 透传**,必须显式绑定 `$attrs`,否则报错。 ### ❌ 错误示例(运行时报错): ```vue <template> <header>Header</header> <main>Content</main> <footer>Footer</footer> </template> ``` ```vue <CustomLayout class="layout" @click="onClick" /> ``` ⚠️ 报错:`Expects exactly one root element or template`. --- ### ✅ 正确做法: ```vue <template> <header>Header</header> <main v-bind="$attrs">Content</main> <footer>Footer</footer> </template> ``` 或选择性绑定特定属性: ```vue <main :class="$attrs.class" @click="$attrs.onClick">Content</main> ``` --- ## 7. 在 JavaScript 中访问透传 Attributes ### 使用 `useAttrs()` API(推荐) ```vue <script setup> import { useAttrs, onUpdated } from 'vue' const attrs = useAttrs() // 注意:$attrs 不是响应式的 onUpdated(() => { console.log('Current attrs:', attrs) }) </script> ``` ### 非 script-setup 写法 ```js export default { setup(props, ctx) { console.log(ctx.attrs) // 透传 attributes } } ``` 📌 提醒:不可依赖 `$attrs` 响应性;需响应式请用 `props`。 --- ## 8. 图表示意:Attributes 透传流程图 ```mermaid graph TD A[父组件传入 attribute] --> B{是否在子组件中声明?} B -->|否| C[视为透传 attribute] B -->|是| D[作为 prop/emits 被消费] C --> E{子组件模板结构} E -->|单根节点| F[自动绑定到根元素] E -->|多根节点| G[必须手动 v-bind='$attrs', 否则警告] E -->|inheritAttrs: false| H[完全控制绑定位置] H --> I[使用 v-bind='$attrs' 分发] ``` --- ## 9. 实际案例分析 ### ✅ 案例一:基础透传(单根 + class 合并) ```vue <!-- ChildButton.vue --> <template> <button class="default-btn">Submit</button> </template> ``` ```vue <!-- Parent.vue --> <ChildButton class="success" /> ``` ➡️ 输出: ```html <button class="default-btn success">Submit</button> ``` --- ### ✅ 案例二:禁用继承并手动分发 ```vue <!-- WrappedInput.vue --> <script setup> defineOptions({ inheritAttrs: false }) </script> <template> <div class="input-group"> <input type="text" v-bind="$attrs" /> </div> </template> ``` ```vue <!-- 使用 --> <WrappedInput placeholder="Enter name" class="custom-input" @input="onInput" /> ``` ➡️ 结果: ```html <div class="input-group"> <input type="text" placeholder="Enter name" class="custom-input" @input="..."> </div> ``` --- ### ✅ 案例三:多根组件显式绑定 ```vue <!-- Layout.vue --> <template> <header>Top</header> <main v-bind="$attrs">Main Content</main> <footer>Bottom</footer> </template> ``` ```vue <Layout class="dark-mode" @click="toggleTheme" /> ``` ➡️ `<main>` 元素获得 `class` 和 `click` 事件。 --- ## 10. 总结归纳 | 特性 | 行为说明 | |------|---------| | 单根组件 | attributes 自动继承至根元素 | | 多根组件 | 必须手动 `v-bind="$attrs"`,否则警告 | | class/style | 与本地值进行智能合并 | | v-on 事件 | 透传并叠加执行 | | inheritAttrs: false | 关闭自动继承,实现精准控制 | | $attrs | 访问所有透传属性(非响应式) | | useAttrs() | Composition API 中获取 $attrs | --- ## 11. 关键知识点详解 - **透传 attribute 的继承机制** Vue 自动将未声明的 attribute 添加到组件根元素,适用于 class、style、id 等。 - **$attrs 的作用与限制** 包含所有未被消费的 attribute,可用于手动绑定,但非响应式,不可侦听变化。 - **多根节点的绑定要求** 多个根元素时必须显式使用 `v-bind="$attrs"`,否则会抛出运行时警告。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值