首页 > 其他分享 >ssts-hospital-web-master项目实战记录三十二:项目迁移-Vue项目Hook和插件的区别

ssts-hospital-web-master项目实战记录三十二:项目迁移-Vue项目Hook和插件的区别

时间:2024-02-27 09:12:29浏览次数:22  
标签:web 插件 Vue 函数 自定义 项目 Hook 使用 组件

记录时间:2024-02-27

一、准备工作

【使用“文心一言”搜索】

Vue 3中的Hook(如setup、onMounted、onUpdated等)具体是如何工作的?它们与组件的生命周期有何关联?

Vue 3引入了Composition API,这是一种新的、可选的方式来组织和重用Vue组件的逻辑。在Composition API中,Hook(如setuponMountedonUpdated等)是核心的概念。

  1. setup

setup是Composition API的入口点。当组件实例被创建时,setup是第一个被调用的函数。这个函数接收两个参数:propscontextprops是组件接收的属性,它是一个响应式对象,我们可以在setup函数内部使用它。context是一个包含了组件的上下文信息的对象,例如attrsslotsemit等。

setup函数返回一个对象,这个对象包含了我们想要在组件的模板或者其它组合式API函数中使用的状态和函数。
2. onMounted

onMounted是一个生命周期Hook,它会在组件被挂载到DOM后立即调用。换句话说,当组件的模板已经被渲染成实际的DOM元素并插入到页面中时,onMounted就会被触发。我们可以在这个函数内部执行一些需要在组件挂载后才能进行的操作,比如获取DOM元素的引用或者发送网络请求等。
3. onUpdated

onUpdated也是一个生命周期Hook,它会在组件的DOM更新后被调用。当组件的状态发生变化,Vue会重新渲染组件的模板以反映这些变化。一旦DOM更新完成,onUpdated就会被触发。我们可以在这个函数内部执行一些需要在DOM更新后才能进行的操作。

这些Hook与组件的生命周期有密切的关联。在Vue 2中,我们通过在组件的选项(如mountedupdated等)中定义函数来访问这些生命周期钩子。在Vue 3中,我们使用这些Hook函数来达到同样的目的,但是它们提供了更好的逻辑组织和重用性。

总的来说,Vue 3中的这些Hook让我们能够以一种更灵活、更直观的方式来组织和处理组件的逻辑和生命周期。


如何使用Vue 3的Hook来优化组件的性能和可维护性?

Vue 3 的 Composition API 和其提供的 Hooks 允许我们以更灵活和组织化的方式来编写组件逻辑,从而优化组件的性能和可维护性。以下是一些使用 Vue 3 Hooks 来优化组件的建议:

  1. 逻辑复用与抽象:
    • 使用 setup 函数来定义和返回组件中需要的响应式状态和函数。
    • 将相关的逻辑代码组织到一个或多个可复用的函数中,这些函数可以使用其他 Hooks(如 refreactivecomputed 等)来创建响应式数据。
    • 通过将这些函数导出为可复用的 Hooks,可以在多个组件之间共享逻辑,提高代码的可维护性。
  2. 精确控制更新:
    • 使用 watch 和 watchEffect Hooks 来精确监听数据变化,并在必要时触发更新。
    • 通过为 watch 提供依赖项数组,可以确保只在相关依赖变化时执行回调,避免不必要的计算。
    • 利用 watchEffect 的 onInvalidate 函数来清理副作用,确保在组件卸载或相关依赖变化时释放资源。
  3. 异步操作和副作用管理:
    • 使用 onMounted 和 onUpdated Hooks 来处理需要在组件特定生命周期阶段执行的异步操作或副作用。
    • 利用 onErrorCaptured Hook 来全局处理子组件中未被捕获的错误。
    • 对于需要长时间运行的操作(如定时器、事件监听器、订阅等),确保在 onBeforeUnmount 或 unmounted Hook 中进行清理。
  4. 条件性渲染和懒加载:
    • 结合 v-if 和 v-show 指令以及响应式数据来控制组件的条件性渲染,避免不必要的渲染开销。
    • 使用动态导入(import())和异步组件来实现组件的懒加载,提高页面初始加载性能。
  5. 性能分析和调试:
    • 利用 Vue Devtools 进行性能分析,找出性能瓶颈并进行优化。
    • 在开发过程中使用 console.time 和 console.timeEnd 来测量代码块的执行时间,帮助定位性能问题。
  6. 类型安全和代码提示:
    • 如果使用 TypeScript,可以利用类型注解来提高代码的类型安全性,减少运行时错误。
    • 结合 IDE 的代码提示功能,可以快速发现和修复潜在的代码问题。
  7. 组件通信:
    • 使用 provide 和 inject Hooks 来实现跨组件的数据共享和通信,避免通过冗长的 props 链进行数据传输。
    • 对于需要全局共享的状态,可以考虑使用 Vuex 或其他全局状态管理库。
  8. 代码分割和模块化:
    • 将大型组件拆分为多个小型、功能单一的组件,提高代码的可维护性和可重用性。
    • 利用模块化编程的思想,将相关代码组织到同一个模块中,方便管理和维护。

通过遵循这些最佳实践,你可以利用 Vue 3 的 Hooks 来编写性能更好、更易于维护的组件代码。


Vue中的Hook与React中的Hook有何异同?它们的设计理念和使用场景有何区别?

Vue中的Hook和React中的Hook都是用于组织和复用组件逻辑的工具,但它们在设计理念、实现方式和使用场景上存在一些异同。

设计理念:

  1. Vue的Hook:Vue的Hook(如setuponMounted等)是基于Vue 3的Composition API构建的,其设计初衷是为了解决Vue 2中Options API在复杂组件中代码组织和逻辑复用的问题。Vue的Hook更注重细粒度的响应性系统和逻辑的组织。

  2. React的Hook:React的Hook(如useStateuseEffect等)是为了在不引入类组件的情况下,让函数组件能够拥有类似类组件的状态和生命周期管理能力。React的Hook强调函数式编程和不可变数据。

实现方式:

  1. Vue的Hook:Vue的Hook底层是基于Vue的响应式系统实现的,通过Proxy对象来追踪数据的变化,并在需要时触发组件的重新渲染。Vue的Hook没有严格的调用顺序要求,可以在条件语句中使用,且不会在每次渲染时重复执行。

  2. React的Hook:React的Hook底层是基于链表实现的,每次组件渲染时都会顺序执行所有的Hook。因此,React的Hook有严格的调用顺序要求,不能在条件语句中使用。此外,React的Hook在每次渲染时都会重新执行,这可能导致不必要的计算和性能问题。

使用场景:

  1. Vue的Hook:Vue的Hook适用于需要组织和复用复杂逻辑的组件。通过使用setup函数和其他Hook,可以将相关的逻辑代码组织到一个可复用的函数中,提高代码的可维护性和可读性。此外,Vue的Hook还适用于需要精确控制组件更新和副作用的场景。

  2. React的Hook:React的Hook适用于需要管理状态和副作用的函数组件。通过使用useStateuseEffect等Hook,可以让函数组件拥有类似类组件的功能,同时保持函数组件的简洁和易读性。React的Hook还适用于需要共享逻辑的场景,通过将逻辑代码封装到自定义Hook中,可以在多个组件之间共享这些逻辑。

总的来说,Vue中的Hook和React中的Hook都是为了解决组件逻辑组织和复用的问题而设计的。它们在设计理念、实现方式和使用场景上存在一些差异,但都是为了提高组件的性能和可维护性而服务的。选择使用哪种Hook取决于你的项目需求和个人偏好。


如何在Vue的Hook中实现数据的响应式处理和状态管理?

在Vue 3中,使用Composition API的Hook来实现数据的响应式处理和状态管理非常直观和灵活。以下是如何在Vue的Hook中实现这些功能的基本步骤:

1. 响应式数据

使用refreactive函数来创建响应式数据。

javascript复制代码
  import { ref, reactive } from 'vue';
   
  export default {
  setup() {
  // 使用 ref 创建一个响应式的单个值
  const count = ref(0);
   
  // 使用 reactive 创建一个响应式的对象
  const state = reactive({
  name: 'Alice',
  age: 30,
  });
   
  // 返回要在模板中使用的响应式数据
  return {
  count,
  state,
  };
  },
  };

2. 状态管理

在Vue组件内部,你可以直接在setup函数中管理状态。对于更复杂的状态管理需求,你可能需要使用Vuex或其他状态管理库。但是,在小型到中型应用中,你也可以使用reactiveref结合provideinject来实现简单的状态共享。

javascript复制代码
  // 父组件
  import { provide, reactive } from 'vue';
   
  export default {
  setup() {
  // 创建一个响应式的状态对象
  const sharedState = reactive({
  user: null,
  loading: false,
  });
   
  // 使用 provide 来共享状态
  provide('sharedState', sharedState);
   
  // ...其他逻辑
  },
  };
   
  // 子组件
  import { inject } from 'vue';
   
  export default {
  setup() {
  // 使用 inject 来接收共享的状态
  const sharedState = inject('sharedState');
   
  // 现在你可以在子组件中使用 sharedState
  // ...其他逻辑
   
  return {
  sharedState,
  };
  },
  };

3. 响应式数据的更新和监听

你可以直接更新响应式数据,Vue会自动追踪依赖并重新渲染相关的组件。你还可以使用watchwatchEffect来监听数据的变化并执行相应的逻辑。

javascript复制代码
  import { ref, watch, watchEffect } from 'vue';
   
  export default {
  setup() {
  const count = ref(0);
   
  // 使用 watch 监听特定的响应式数据
  watch(count, (newValue, oldValue) => {
  console.log(`Count changed from ${oldValue} to ${newValue}`);
  });
   
  // 使用 watchEffect 监听 setup 函数中使用的所有响应式数据
  watchEffect(() => {
  console.log(`Count is now ${count.value}`);
  });
   
  // 返回一个方法用来增加 count 的值
  function increment() {
  count.value++;
  }
   
  return {
  count,
  increment,
  };
  },
  };

4. 跨组件通信和状态共享

对于更复杂的跨组件通信和状态共享需求,你可能需要使用Vuex或Vue 3提供的provide/inject机制,或者使用第三方库如Mitt、TinyEmitter等来实现事件总线模式。

Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

在Vue 3中,provideinject得到了改进,可以更灵活地用于跨组件共享数据,而不仅仅是用于高阶组件和它们的子组件之间。这使得在没有使用Vuex的情况下实现状态管理成为可能,尤其是对于小型和中等规模的应用程序。


Vue的Hook函数与普通的JavaScript函数在写法和使用上有什么不同?

Vue的Hook函数和普通的JavaScript函数在写法和使用上的确有一些明显的区别。以下是这些区别的一些关键点:

  1. 设计目的:

    • Vue的Hook函数:Vue的Hook函数(如setuponMountedonUpdated等)是Vue 3 Composition API的一部分,它们被设计用来组织和复用Vue组件的逻辑。这些Hook函数允许你以更细粒度的方式控制组件的生命周期、状态、和副作用。
    • 普通的JavaScript函数:普通的JavaScript函数则没有这样的特定目的。它们可以用于执行任何类型的计算或操作,包括在Vue组件外部执行逻辑。
  2. 响应性:

    • Vue的Hook函数:在Vue的Hook函数中,你可以使用refreactive等函数来创建响应式的数据。当这些数据变化时,Vue会自动更新DOM。
    • 普通的JavaScript函数:普通的JavaScript函数不自带响应性。你需要手动处理数据的变化和DOM的更新。
  3. 使用场景:

    • Vue的Hook函数:Vue的Hook函数主要在Vue组件的setup函数中使用,用于替代Vue 2.x中的Options API(如datamethodscomputed等)。它们使得组件逻辑更加组织化、清晰和可维护。
    • 普通的JavaScript函数:普通的JavaScript函数可以在任何JavaScript环境中使用,包括在Vue组件内部和外部。
  4. 函数签名和调用方式:

    • Vue的Hook函数:Vue的Hook函数通常作为Vue组件的一部分被调用,并且它们通常接受特定的参数(如propscontext等)。例如,setup函数是Vue组件的一个特殊Hook,它在组件实例被创建之前调用,并接受propscontext作为参数。
    • 普通的JavaScript函数:普通的JavaScript函数可以根据需要定义任何数量的参数,并且可以在任何需要的地方被调用。
  5. 生命周期关联:

    • Vue的Hook函数:一些Vue的Hook函数(如onMountedonUpdatedonUnmounted等)与Vue组件的生命周期紧密相关。它们在组件的特定生命周期阶段被自动调用。
    • 普通的JavaScript函数:普通的JavaScript函数没有与任何特定的生命周期关联。你需要手动调用它们,并管理它们的执行时间和顺序。
  6. 状态管理:

    • Vue的Hook函数:在Vue的Hook函数中,你可以使用reactiveref等函数来创建和管理状态。这些状态可以在组件的模板和其他Hook函数中使用。
    • 普通的JavaScript函数:在普通的JavaScript函数中,你需要使用其他方式来管理状态,例如使用普通的JavaScript变量或对象,或者使用外部的状态管理库(如Redux、MobX等)。但是,这些状态不会自动与Vue组件的模板或其他部分同步。


有没有一些实用的Vue Hook库或插件推荐?它们能为项目带来哪些便利?

当谈到实用的Vue Hook库或插件时,确实有一些值得推荐的选项。这些库和插件可以极大地提高Vue项目的开发效率和便利性。以下是一些建议的库和插件,以及它们能为项目带来的便利:

  1. Vue Composition API:
    • 虽然这不是一个外部库,但Vue 3内置的Composition API提供了一系列Hook函数(如refreactivecomputedwatchonMounted等),使得组件逻辑的组织和复用更加灵活和高效。
    • 通过使用这些Hook,开发者可以更细粒度地控制组件的状态和生命周期,同时减少重复代码和逻辑。
  2. vue-use:
    • vue-use是一个基于Composition API的实用Hook集合,提供了许多现成的、可复用的Hook函数。
    • 它包含诸如useMouseuseKeyPressuseIntervaluseDebounce等Hook,可以方便地处理用户输入、定时任务、动画等常见场景。
    • 使用vue-use可以加速开发过程,减少造轮子的时间,并确保代码的质量和可维护性。
  3. vue-router(对于路由管理):
    • 虽然vue-router不是一个Hook库,但它是Vue生态系统中必不可少的路由管理工具。
    • 结合Composition API的Hook(如useRouteuseRouter),开发者可以更方便地在组件中访问和操作路由信息。
    • 这使得导航守卫、路由参数获取、编程式导航等任务更加简单和直观。
  4. Vuex(对于状态管理):
    • Vuex是Vue.js应用的状态管理模式和库。它集中存储应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
    • 虽然Vuex本身不直接提供Hook函数,但它与Vue的Composition API结合得非常紧密。通过使用如useStore这样的Hook函数,可以方便地在组件中访问和操作Vuex store中的状态。
    • Vuex确保了应用的状态管理是可预测和可维护的,特别适用于中大型应用。
  5. vue-wait:
    • vue-wait是一个处理异步操作和加载状态的Hook库。
    • 它提供了useWait等Hook函数,用于简化异步操作期间的加载状态、错误处理和重试逻辑。
    • 使用vue-wait可以减少模板和逻辑中的冗余代码,使异步操作的处理更加清晰和一致。
  6. 自定义Hook库:
    • 除了上述库之外,开发者还可以根据项目需求创建自定义的Hook库。
    • 例如,可以封装与特定API交互的逻辑、处理表单验证、创建自定义的动画Hook等。
    • 自定义Hook库有助于将项目的特定逻辑抽象为可复用的函数,从而提高代码的可维护性和可读性。

这些库和插件能够极大地提升Vue项目的开发效率和代码质量。通过使用现成的、经过优化的Hook函数,开发者可以专注于实现项目的核心功能,而无需花费大量时间处理底层细节和常见任务。此外,这些库和插件还提供了清晰的文档和社区支持,有助于解决开发过程中遇到的问题。


如何自定义Vue的Hook,并在项目中复用这些自定义Hook?

自定义Vue的Hook是一个很好的实践,它可以帮助你封装和复用组件逻辑,提高代码的可读性和可维护性。以下是如何自定义Vue的Hook并在项目中复用它们的步骤:

1. 创建一个自定义Hook

自定义Hook是一个函数,它使用Vue的Composition API中的其他Hook来封装特定的功能或行为。自定义Hook通常以“use”为前缀,以符合Vue的命名约定。

javascript复制代码
  import { ref, onMounted, onUnmounted } from 'vue';
   
  export function useCustomHook(initialValue) {
  const state = ref(initialValue);
   
  const updateState = (newValue) => {
  state.value = newValue;
  };
   
  onMounted(() => {
  console.log('Custom hook mounted');
  // 这里可以放置一些组件挂载后的逻辑
  });
   
  onUnmounted(() => {
  console.log('Custom hook unmounted');
  // 这里可以放置一些组件卸载前的清理逻辑
  });
   
  return {
  state,
  updateState,
  };
  }

2. 在组件中使用自定义Hook

在你的Vue组件中,你可以像使用其他Hook一样使用自定义Hook。只需要导入它,并在setup函数中调用它即可。

javascript复制代码
  <script>
  import { useCustomHook } from './useCustomHook'; // 假设你的自定义Hook在同一个目录下
   
  export default {
  setup() {
  // 使用自定义Hook,并传入初始值(如果需要的话)
  const { state, updateState } = useCustomHook('initial value');
   
  // ... 其他逻辑
   
  return {
  state,
  updateState,
  };
  },
  };
  </script>

3. 复用自定义Hook

自定义Hook的真正威力在于它们可以在多个组件中轻松复用。只要将自定义Hook放在一个可访问的模块中,你就可以在项目的任何组件中导入和使用它。

例如,如果你有一个管理用户认证状态的自定义Hook,你可以在应用的不同部分(如导航栏、用户面板、登录表单等)导入和使用它,而无需在每个组件中重复相同的逻辑。

4. 组合多个自定义Hook

你还可以组合多个自定义Hook来创建更复杂的逻辑。每个自定义Hook都可以专注于一个特定的功能或行为,然后你可以将它们组合在一起以构建更强大的功能。

注意事项:

  • 自定义Hook应该尽可能地通用和可配置,以便在不同的上下文中使用。
  • 避免在自定义Hook中直接使用DOM操作或全局状态管理(如直接修改window对象或Vuex store),以保持其可测试性和可移植性。相反,应该通过参数和返回值与外部环境进行交互。
  • 如果自定义Hook需要在多个组件之间共享状态,考虑使用Vuex或其他状态管理库来管理这些共享状态。


Vue的Hook在开发大型或复杂应用时有哪些优势?它们如何提升代码的可读性和可维护性?

Vue的Hook在开发大型或复杂应用时具有显著的优势,它们能够极大地提升代码的可读性和可维护性。以下是具体的优势说明:

  1. 逻辑复用与解耦:通过自定义Hook,可以将常用的逻辑或状态封装起来,并在多个组件中复用。这不仅避免了重复的代码编写,还使得这些逻辑更容易被测试和维护。同时,Hook允许我们将组件内的逻辑拆分成更小的函数,每个函数都专注于特定的功能,这使得代码更加解耦,降低了组件的复杂性。
  2. 清晰的代码结构:使用Hook可以使组件的代码结构更加清晰。在Vue 2.x中,组件的选项(如datamethodscomputed等)是按类型组织的,而不是按功能或逻辑组织的。这可能导致相关的代码被分散在不同的选项中,难以阅读和维护。而Hook则允许我们按功能或逻辑组织代码,使得相关的代码更加集中,更易于阅读和理解。
  3. 更好的响应性管理:Vue 3的Composition API提供了更加细粒度的响应性管理。通过使用refreactive等Hook,我们可以精确地控制哪些数据是响应式的,以及何时更新DOM。这避免了不必要的渲染和计算,提高了应用的性能。同时,这些Hook也使得状态的管理更加明确和可预测,降低了出错的可能性。
  4. 易于测试和调试:由于Hook函数都是纯函数,它们不依赖于组件的实例或全局状态,因此更容易进行单元测试。此外,由于每个Hook函数都有明确的功能和输入/输出,这使得在调试时更容易定位和解决问题。
  5. 与TypeScript的更好集成:Vue 3的Composition API与TypeScript的集成更加紧密。通过使用TypeScript的类型注解和类型推断功能,我们可以为Hook函数的参数和返回值提供明确的类型信息,从而提高了代码的类型安全性和可维护性。

总的来说,Vue的Hook通过提供一种更加灵活和组织化的方式来编写组件逻辑,使得代码更加清晰、可维护和可扩展。在开发大型或复杂应用时,这些优势将更加明显。

 

 

翻译

搜索

复制

<iframe height="240" width="320"></iframe>

标签:web,插件,Vue,函数,自定义,项目,Hook,使用,组件
From: https://www.cnblogs.com/lizhigang/p/18036109

相关文章

  • Vue3 [1] Vite + element-plus +Vue3 项目搭建、"@"别名设置
    1.环境准备node官网npm切换国内npm源镜像npmconfigsetregistryhttps://registry.npmmirror.com查看当前的镜像源npmconfiggetregistryvscode插件扩展包VueVolarextensionPack2.项目初始化本项目使用vite进行构建,vite官方中文文档参考:cn.......
  • linux练手小项目:探测系统信息
    看了b站上的一个教学视频,复习了一下拿取linux系统信息的方法,并跟着up写了一个小的脚本完成一系列需求。写一篇博文记录一下这个过程,以后回顾用。课程地址:https://www.bilibili.com/video/BV1L7421T7mc课程课件:https://gitee.com/coldbloodx/lsbs需求显示当前运行的操作系......
  • 基于乳腺癌的预测(SVM实战项目)
    2024.2.26今天,我在学习机器学习重要的知识点——SVM(支持向量机)首先,我利用sklearn库中自带的数据集练手点击查看代码importpandasaspdimportseabornassnsimportmatplotlib.pyplotaspltfromsklearn.datasetsimportload_breast_cancerfromsklearn.model_sele......
  • GitHub项目如何快速稳定涨星,让Star飞一会
    GitHub现在已经成了日常开发中必不可少的网站,日常工作和学习中要用到好多上面的开源项目,评价项目质量好坏的一个重要标准就是看Star和Fork的数量,如果看到个Star超过100以上的,基本上这个项目是靠谱的,如果超过1000过,那已经算是很流行了,至于一万以上的,基本上都是如雷贯耳的存在了。......
  • Eplan插件 - 页描述批量编辑器
    前言在工作中,我们经常会遇到修改页描述属性的情况,比如从其他项目复制了页或者是新建了多页。但是在Eplan中,没有办法直接批量编辑页描述属性。通常我们有以下两种方法来批量修改属性。1.修改高层代号/位置代号中的页描述属性在这里我们可以选择顶层的文档类型代号,点击属性在......
  • 【Django开发】0到1开发美多shop项目:用户登录模块开发。全md文档笔记(附代码 文档)
    本系列文章md笔记(已分享)主要讨论django商城项目相关知识。项目利用Django框架开发一套前后端不分离的商城项目(4.0版本)含代码和文档。功能包括前后端不分离,方便SEO。采用Django+Jinja2模板引擎+Vue.js实现前后端逻辑,Nginx服务器(反向代理)Nginx服务器(静态首页、商品详情页、uwsg......
  • 在typescript项目中什么场景适合定义枚举值,什么场景适合定义常量类?
    在typescript项目中什么场景适合定义枚举值,什么场景适合定义常量类在TypeScript中,枚举(enum)和常量类(通常是带有只读属性的类)都有其适用场景:适合定义枚举值的场景:有限且命名的集合:当你需要表示一组固定的、可枚举的值,并且每个值都有一个明确的名字时,使用枚举类型是合适的。......
  • Jenkins插件开发遇到的问题
    创建模板问题很多教程都是使用这个命令去创建Jenkins插件项目mvn-Uarchetype:generate-Dfilter=io.jenkins.archetypes:我使用这个命令,会报archetype不存在[WARNING]Noarchetypefoundinremotecatalog.Defaultingtointernalcatalog可以使用官方提供的非互动式......
  • DevExtreme项目相关记录
    1.DxDataGrid是网格(表格标签) 如上图所示:里面的属性意思如下:data-source:动态的数据源show-borders:用于控制是否显示表格单元格之间的边框column-width:设置列的最小宽度key-expr: 用于指定数据项的唯一标识符的表达式allow-column-reordering:是否允许列于列......
  • springboot项目启动失败
    对于springboot项目默认启动的时候,终端日志什么错误信息都没有打印,直接就启动失败了,就看到这么一句提示springbootProcessfinishedwithexitcode1这样我们确实不知道失败原因在哪里,我们可以这样调试,把错误找出来。在启动类里面加上trycatch语句 我们接着启动项目,从......