Vue基础(2)

news2025/1/25 19:43:09

19、组件之间传递数据

组件与组件之间不是完全独立的,而是有交集的,那就是组件与组 件之间是可以传递数据的 传递数据的解决方案就是 props

ComponentA.vue

<template>
  <!-- 使用ComponentB组件,并传递title属性 -->
  <h3>ComponentA</h3>
  <ComponentB title="传递数据"/>
</template>

<script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";

export default {
  // 定义组件选项对象
  components: {
    // 将ComponentB注册为当前组件的局部组件
    ComponentB
  }
};
</script>

ComponentB.vue 

<template>
  <!-- 使用props接收来自父组件的title属性 -->
  <h3>ComponentB</h3>
  <p>{
  
  { title }}</p>
</template>

<script>
export default {
  // 定义组件选项对象
  props: ["title"]
};
</script>

动态数据传递

<template>
  <!-- 使用ComponentA和ComponentB组件 -->
  <h3>ComponentA</h3>
  <!-- 将父组件的数据message传递给ComponentB -->
  <ComponentB :title="message" />
</template>

<script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";

export default {
  // 定义组件选项对象
  data() {
    return {
      message: "动态数据" // 定义数据message
    };
  },
  components: {
    ComponentB // 将ComponentB注册为当前组件的局部组件
  }
};
</script>

注意事项:

props 传递数据,只能从父级传递到子级,不能反其道而行

组件传递多种数据类型

通过 props 传递数据,不仅可以传递字符串类型的数据,还可以是其 他类型,例如:数字、对象、数组等 但实际上任何类型的值都可以作为 props 的值被传递.

传递Number类型

ComponentA.vue

<template>
  <!-- 显示ComponentA标题 -->
  <h3>ComponentA</h3>
  <!-- 使用ComponentB组件,并传递age属性 -->
  <ComponentB :age="age"/>
</template>

<script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";

export default {
  data() {
    return {
      age: 20 // 定义数据age
    };
  },
  components: {
    ComponentB // 将ComponentB注册为当前组件的局部组件
  }
};
</script>

 ComponentB.vue

<template>
  <!-- 显示ComponentB标题 -->
  <h3>ComponentB</h3>
  <!-- 显示从父组件传递过来的age属性 -->
  <p>{
  
  { age }}</p>
</template>

<script>
export default {
  props: ["age"] // 定义props接收来自父组件的age属性
};
</script>

传递Array类型

ComponentA.vue

<template>
  <!-- 显示ComponentA标题 -->
  <h3>ComponentA</h3>
  <!-- 使用ComponentB组件,并传递names属性 -->
  <ComponentB :names="names" />
</template>

<script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";

export default {
  data() {
    return {
      names: ["iwen", "ime", "frank"] // 定义数据names
    };
  },
  components: {
    ComponentB // 将ComponentB注册为当前组件的局部组件
  }
};
</script>

 ComponentB.vue

<template>
  <!-- 显示ComponentB标题 -->
  <h3>ComponentB</h3>
  <!-- 使用v-for指令遍历names数组,并显示每个元素 -->
  <p v-for="(item, index) of names" :key="index">{
  
  { item }}</p>
</template>

<script>
export default {
  props: ["names"] // 定义props接收来自父组件的names属性
};
</script>

传递Object类型

ComponentA.vue

<template>
  <!-- 显示ComponentA标题 -->
  <h3>ComponentA</h3>
  <!-- 使用ComponentB组件,并传递userInfo属性 -->
  <ComponentB :userInfo="userInfo" />
</template>

<script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";

export default {
  data() {
    return {
      userInfo: { // 定义数据userInfo
        name: "iwen",
        age: 20
      }
    };
  },
  components: {
    ComponentB // 将ComponentB注册为当前组件的局部组件
  }
};
</script>

 ComponentB.vue

<template>
  <!-- 显示ComponentB标题 -->
  <h3>ComponentB</h3>
  <!-- 显示从父组件传递过来的userInfo.name属性的值 -->
  <p>{
  
  { userInfo.name }}</p>
  <!-- 显示从父组件传递过来的userInfo.age属性的值 -->
  <p>{
  
  { userInfo.age }}</p>
</template>

<script>
export default {
  props: ["userInfo"] // 定义props接收来自父组件的userInfo属性
};
</script>

组件传递Props效验

Vue 组件可以更细致地声明对传入的 props 的校验要求

ComponentA.vue

<template>
  <!-- 显示ComponentA标题 -->
  <h3>ComponentA</h3>
  <!-- 使用ComponentB组件,并传递title和userInfo属性 -->
  <ComponentB title="Props效验" :userInfo="userInfo" />
</template>

<script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue";

export default {
  data() {
    return {
      userInfo: { // 定义数据userInfo
        name: "iwen",
        age: 20
      }
    },
  components: {
    ComponentB // 将ComponentB注册为当前组件的局部组件
  }
};
</script>

ComponentB.vue

<template>
  <!-- 显示ComponentB标题 -->
  <h3>ComponentB</h3>
  <!-- 显示从父组件传递过来的title属性的值 -->
  <p>{
  
  { title }}</p>
  <!-- 显示从父组件传递过来的userInfo.name属性的值 -->
  <p>{
  
  { userInfo.name }}</p>
  <!-- 显示从父组件传递过来的userInfo.age属性的值 -->
  <p>{
  
  { userInfo.age }}</p>
</template>

<script>
export default {
  props: { // 定义props接收来自父组件的title和userInfo属性
    title: {
      type: String
    },
    userInfo: {
      type: Object
    }
  }
};
</script>

默认值default

<template>
  <!-- 显示ComponentB标题 -->
  <h3>ComponentB</h3>
  <!-- 显示从父组件传递过来的title属性的值 -->
  <p>{
  
  { title }}</p>
  <!-- 显示从父组件传递过来的userInfo.name属性的值 -->
  <p>{
  
  { userInfo.name }}</p>
  <!-- 显示从父组件传递过来的userInfo.age属性的值 -->
  <p>{
  
  { userInfo.age }}</p>
  <!-- 显示从父组件传递过来的age属性的值 -->
  <p>{
  
  { age }}</p>
</template>

<script>
export default {
  // 定义props选项,接收来自父组件的title、userInfo和age属性
  props: {
    title: {
      type: String // title属性的类型为String
    },
    userInfo: {
      type: Object, // userInfo属性的类型为Object
      default() {
        return {} // 默认值为空对象
      }
    },
    age: {
      type: Number, // age属性的类型为Number
      default: 20 // 默认值为20
    }
  }
};
</script>

必选项required

<template>
  <!-- 显示ComponentB标题 -->
  <h3>ComponentB</h3>
  <!-- 显示从父组件传递过来的title属性的值 -->
  <p>{
  
  { title }}</p>
  <!-- 显示从父组件传递过来的userInfo.name属性的值 -->
  <p>{
  
  { userInfo.name }}</p>
  <!-- 显示从父组件传递过来的userInfo.age属性的值 -->
  <p>{
  
  { userInfo.age }}</p>
  <!-- 显示从父组件传递过来的age属性的值 -->
  <p>{
  
  { age }}</p>
</template>

<script>
export default {
  // 定义props选项,接收来自父组件的title、userInfo和age属性
  props: {
    title: {
      type: String, // title属性的类型为String
      required: true // title属性是必需的
    },
    userInfo: {
      type: Object, // userInfo属性的类型为Object
     // 对象或者数组应当用工厂函数返回
     default() {
       return {} // 默认值为空对象
     }
   },
  age: {
    type: Number, // age属性的类型为Number
    default: 20 // 默认值为20
  }
};
</script>

在Vue.js中,prop 是一种特殊的数据属性,用于父组件向子组件传递数据。prop 是只读的,这意味着子组件不能修改从父组件接收到的 prop 数据。如果尝试修改 prop 的值,Vue 会发出警告信息,提示 prop 是只读的。

20、组件事件

在Vue.js框架中,组件之间的通信是一个常见的需求。$emit方法就是用来在组件的模板表达式中触发自定义事件的,这使得父子组件之间可以进行通信。通过这种方式,子组件可以向父组件发送消息,比如通知某个操作已经完成,或者请求父组件执行某个操作。

自定义事件的触发可以用于多种目的,其中之一就是组件之间传递数据。例如,当用户在子组件中进行某种操作时,子组件可以通过$emit方法向父组件发送一个事件,携带必要的数据。父组件可以监听这个事件,并在事件触发时接收数据,从而实现数据的传递。

父组件(ComponentA.vue)

<template>
  <!-- 显示标题 -->
  <h3>ComponentA</h3>
  <!-- 引入子组件ComponentB,并监听名为some-event的自定义事件 -->
  <ComponentB @some-event="getHandle"/>
  <!-- 显示从子组件接收到的数据 -->
  <p>ComponentA接受的数据: {
  
  { message }}</p>
</template>

<script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue"

export default {
  data() {
    return {
      // 初始化一个空字符串用于存储从子组件接收到的数据
      message: ""
    }
  },
  components: {
    // 注册子组件ComponentB
    ComponentB
  },
  methods: {
    // 定义一个方法getHandle,用于处理从子组件接收到的数据
    getHandle(data) {
      this.message = data; // 将接收到的数据赋值给message属性
    }
  }
}
</script>

子组件(ComponentB.vue)

<template>
  <!-- 显示标题 -->
  <h3>ComponentB</h3>
  <!-- 定义一个按钮,点击时触发sendHandle方法 -->
  <button @click="sendHandle">发送数据</button>
</template>

<script>
export default {
  methods: {
    // 定义一个方法sendHandle,用于触发自定义事件并发送数据
    sendHandle() {
      this.$emit("someEvent", "ComponentB的数据"); // 触发名为someEvent的事件,并传递数据
    }
  }
}
</script>

组件之间传递数据:

  1. 父传子:使用 props

    • 在Vue.js中,props是父组件向子组件传递数据的一种方式。父组件可以通过在子组件标签中定义属性来传递数据,这些属性在子组件内部可以通过props对象访问。

    • 这种方式是单向数据流,确保了数据的流向是从父组件到子组件,有助于避免组件之间的耦合。

  2. 子传父:使用自定义事件 (this.$emit)

    • 当需要从子组件向父组件传递数据时,可以使用自定义事件。子组件通过this.$emit方法触发一个事件,并将数据作为参数传递。父组件需要监听这个事件,并在事件触发时接收数据。

    • 这种方式允许子组件在需要时通知父组件,例如用户交互或数据变化。

组件事件配合 v-model 使用

如果是用户输入,我们希望在获取数据的同时发送数据配合 v-model 来使用

父组件(ComponentA.vue)

<template>
  <div>
    <h3>ComponentA</h3>
    <!-- 使用@some-event监听来自ComponentB的自定义事件 -->
    <componentB @some-event="getHandle"/>
    <!-- 显示从ComponentB接收到的数据 -->
    <p>ComponentA接受的数据: {
  
  { message }}</p>
  </div>
</template>

<script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue"

export default {
  data() {
    return {
      // 初始化message为空字符串,用于存储从子组件接收的数据
      message: ""
    }
  },
  components: {
    // 注册子组件ComponentB
    ComponentB
  },
  methods: {
    // 定义getHandle方法来接收从子组件传递的数据
    getHandle(data) {
      this.message = data;
    }
  }
}
</script>

子组件(ComponentB.vue)

<template>
  <div>
    <h3>ComponentB</h3>
    <!-- 使用v-model绑定输入框的值到searchText -->
    <input v-model="searchText" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 初始化searchText为空字符串
      searchText: ""
    }
  },
  watch: {
    // 监听searchText的变化
    searchText(newVal, oldVal) {
      // 当searchText变化时,触发someEvent事件,并将新值作为参数传递
      this.$emit("someEvent", newVal);
    }
  }
}
</script>

组件数据传递

通常我们使用 props 来实现父组件向子组件的数据传递(单向下行绑定),但Vue.js也提供了一种方式,使得子组件可以通过 props 实现数据的“回传”给父组件,这通常通过使用 .sync 修饰符或在Vue 3中使用 v-model 来实现。

父组件(ParentComponent.vue)

<template>
  <div>
    <h3>ComponentA</h3>
    <!-- 使用:onFnEvent监听来自ChildComponent的自定义事件 -->
    <Child :onFnEvent="fn" />
    <!-- 显示从ChildComponent接收到的数据 -->
    <p>{
  
  { message }}</p>
  </div>
</template>

<script>
// 导入子组件Child
import Child from "./components/Child.vue";

export default {
  data() {
    return {
      // 初始化message为空字符串,用于存储从子组件接收的数据
      message: ""
    }
  },
  methods: {
    // 定义fn方法来接收从子组件传递的数据
    fn(data) {
      this.message = data;
    }
  },
  components: {
    // 注册子组件Child
    Child
  }
}
</script>

子组件(Child.vue)

<template>
  <div>
    <h3>组件传递数据</h3>
    <!-- 调用onFnEvent方法并传递数据 -->
    <p>{
  
  { onFnEvent('测试数据') }}</p>
  </div>
</template>

<script>
export default {
  props: {
    // 定义一个名为onFnEvent的prop,类型为Function
    onFnEvent: {
      type: Function
    }
  }
}
</script>

代码解释

  1. 父组件(ParentComponent.vue):

    • 在模板中,使用<Child :onFnEvent="fn" />标签引入子组件,并使用:onFnEvent="fn"来监听子组件触发的事件。

    • 当子组件触发事件时,父组件的fn方法会被调用,并接收子组件传递的数据。

    • message数据属性用于存储从子组件接收到的数据,并在模板中显示。

  2. 子组件(Child.vue):

    • 在模板中,调用onFnEvent方法并传递数据'测试数据'

    • 定义一个名为onFnEventprop,类型为Function,用于接收父组件传递的事件处理函数。

21、插槽 Slots

我们已经了解到组件能够接收任意类型的 JavaScript 值作为 props,但组件要如何接收模板内容呢?在某些场景中,我们可能 想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这 些片段。

<solt>元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽 内容 (slot content) 将在哪里被渲染.

父组件(ComponentA.vue)

<template>
  <div>
    <h3>ComponentA</h3>
    <!-- 使用ComponentB,并在插槽中传递内容 -->
    <ComponentB>
      <h3>插槽传递视图内容</h3>
    </ComponentB>
  </div>
</template>

<script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";

export default {
  components: {
    // 注册子组件ComponentB
    ComponentB
  }
}
</script>

子组件(ComponentB.vue)

<template>
  <div>
    <h3>ComponentB</h3>
    <!-- 使用<slot>标签来接收从父组件传递的内容 -->
    <slot></slot>
  </div>
</template>

<script>
export default {
  // ComponentB不需要额外的逻辑,只需定义插槽
}
</script>

渲染作用域

插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在 父组件模板中定义的.

父组件(ComponentA.vue)

<template>
  <div>
    <h3>ComponentA</h3>
    <!-- 使用ComponentB,并在插槽中传递内容 -->
    <ComponentB>
      <h3>{
  
  { message }}</h3>
    </ComponentB>
  </div>
</template>

<script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";

export default {
  data() {
    return {
      // 定义message数据属性,用于存储要传递给子组件的内容
      message: "message在父级"
    }
  },
  components: {
    // 注册子组件ComponentB
    ComponentB
  }
}
</script>

子组件(ComponentB.vue)

<template>
  <div>
    <h3>ComponentB</h3>
    <!-- 使用<slot>标签来接收从父组件传递的内容 -->
    <slot></slot>
  </div>
</template>

<script>
export default {
  // ComponentB不需要额外的逻辑,只需定义插槽
}
</script>

默认内容

在外部没有提供任何内容的情况下,可以为插槽指定默认内容.

<template>
  <div>
    <h3>ComponentB</h3>
    <!-- 使用<slot>标签定义插槽,并设置默认内容 -->
    <slot>插槽默认值</slot>
  </div>
</template>

<script>
export default {
  // ComponentB不需要额外的逻辑,只需定义插槽和默认值
}
</script>

具名插槽

父组件(ComponentA.vue)

<template>
  <div>
    <h3>ComponentA</h3>
    <!-- 使用ComponentB,并为header和main插槽传递内容 -->
    <ComponentB>
      <template v-slot:header>
        <h3>标题</h3>
      </template>
      <template v-slot:main>
        <p>内容</p>
      </template>
    </ComponentB>
  </div>
</template>

<script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";

export default {
  data() {
    return {
      // 定义message数据属性,虽然在这个例子中没有用到
      message: "message在父级"
    }
  },
  components: {
    // 注册子组件ComponentB
    ComponentB
  }
}
</script>

子组件(ComponentB.vue)

<template>
  <div>
    <h3>ComponentB</h3>
    <!-- 使用<slot>标签定义具名插槽header -->
    <slot name="header"></slot>
    <hr>
    <!-- 使用<slot>标签定义具名插槽main -->
    <slot name="main"></slot>
  </div>
</template>

<script>
export default {
  // ComponentB不需要额外的逻辑,只需定义具名插槽
}
</script>

代码解释

  1. 父组件(ComponentA.vue):

    • 在模板中,使用<ComponentB>标签引入子组件,并为headermain插槽传递内容。

    • 使用<template v-slot:header><template v-slot:main>来指定内容应该填充到哪个插槽中。

    • ComponentB组件被注册在父组件的components对象中,使其可以在父组件的模板中使用。

  2. 子组件(ComponentB.vue):

    • 在模板中,使用<slot name="header"></slot><slot name="main"></slot>来定义具名插槽。这些插槽用于接收从父组件传递的内容。

    • 当父组件使用<ComponentB>标签并包含具名插槽的内容时,这些内容将替换子组件中的相应插槽标签。

 在Vue.js中,v-slot 指令用于定义插槽,而 # 符号是 v-slot 的简写形式,用于指定插槽的名称。

 父组件(ComponentA.vue)

<template>
  <div>
    <h3>ComponentA</h3>
    <!-- 使用ComponentB,并为header和main插槽传递内容 -->
    <ComponentB>
      <template #header>
        <h3>标题</h3>
      </template>
      <template #main>
        <p>内容</p>
      </template>
    </ComponentB>
  </div>
</template>

<script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";

export default {
  data() {
    return {
      // 定义message数据属性,用于存储要传递给子组件的内容
      message: "message在父级"
    }
  },
  components: {
    // 注册子组件ComponentB
    ComponentB
  }
}
</script>

子组件(ComponentB.vue)

<template>
  <div>
    <h3>ComponentB</h3>
    <!-- 使用<slot>标签定义具名插槽header -->
    <slot name="header"></slot>
    <hr>
    <!-- 使用<slot>标签定义具名插槽main -->
    <slot name="main"></slot>
  </div>
</template>

<script>
export default {
  // ComponentB不需要额外的逻辑,只需定义具名插槽
}
</script>

在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时 将一部分数据提供给插槽 我们也确实有办法这么做!可以像对组件传递 props 那样,向一个 插槽的出口上传递 attributes

父组件(ComponentA.vue)

<template>
  <div>
    <h3>ComponentA</h3>
    <!-- 使用ComponentB,并通过具名插槽slotProps传递数据 -->
    <componentB v-slot="slotProps">
      <h3>{
  
  { message }}-{
  
  { slotProps.text }}</h3>
    </componentB>
  </div>
</template>

<script>
// 导入子组件ComponentB
import ComponentB from "./ComponentB.vue";

export default {
  data() {
    return {
      // 定义message数据属性,用于存储要传递给子组件的内容
      message: "message在父级"
    }
  },
  components: {
    // 注册子组件ComponentB
    ComponentB
  }
}
</script>

子组件(ComponentB.vue)

<template>
  <div>
    <h3>ComponentB</h3>
    <!-- 使用<slot>标签定义具名插槽,并传递message数据 -->
    <slot :text="message"></slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 定义message数据属性,用于存储子组件的数据
      message: "ComponentB中的数据"
    }
  }
}
</script>

代码解释

  1. 父组件(ComponentA.vue):

    • 在模板中,使用<componentB>标签引入子组件,并为slotProps插槽传递内容。

    • 使用<template v-slot="slotProps">来指定内容应该填充到哪个插槽中,并从子组件接收数据。

    • message数据属性用于存储要传递给子组件的内容。

    • ComponentB组件被注册在父组件的components对象中,使其可以在父组件的模板中使用。

  2. 子组件(ComponentB.vue):

    • 在模板中,使用<slot :text="message"></slot>来定义具名插槽。这个插槽用于接收从父组件传递的内容。

    • message数据属性用于存储子组件的数据,并通过插槽传递给父组件。

 具名插槽传递数据

<template>
  <!-- 显示ComponentA的标题 -->
  <h3>ComponentA</h3>
  <!-- 使用ComponentB组件,并通过名为header的slot传递slotProps -->
  <ComponentB #header="slotProps">
    <!-- 显示从父组件传递的消息和slotProps.text -->
    <h3>{
  
  { message }}-{
  
  { slotProps.text }}</h3>
  </ComponentB>
</template>

<script>
// 导入ComponentB组件
import ComponentB from "./ComponentB.vue"

export default {
  data() {
    return {
      // 定义一个消息变量,用于在模板中显示
      message: "message在父级"
    }
  },
  // 定义组件对象,用于注册子组件
  components: {
    ComponentB
  }
}
</script>
<template>
  <!-- 显示ComponentB的标题 -->
  <h3>ComponentB</h3>
  <!-- 使用slot,允许父组件通过名为header的slot传递内容 -->
  <slot name="header" :text="message"></slot>
</template>

<script>
export default {
  data() {
    return {
      // 定义一个消息变量,用于在模板中显示
      message: "ComponentB中的数据"
    }
  }
}
</script>

22、组件生命周期

每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如 设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变 时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函 数,让开发者有机会在特定阶段运行自己的代码。

<template>
  <!-- 显示组件生命周期的标题 -->
  <h3>组件生命周期</h3>
  <!-- 显示message数据 -->
  <p>{
  
  { message }}</p>
  <!-- 一个按钮,点击时调用updateHandle方法更新数据 -->
  <button @click="updateHandle">更新数据</button>
</template>

<script>
export default {
  // data函数返回一个对象,其中包含一个message属性,初始值为"老数据"
  data() {
    return {
      message: "老数据"
    }
  },
  // methods对象包含组件的方法
  methods: {
    // updateHandle方法更新message属性的值为"新数据"
    updateHandle() {
      this.message = "新数据"
    }
  },
  // 生命周期钩子函数
  beforeCreate() {
    // 在组件实例初始化之后调用,此时不能访问data中的属性
    console.log("组件创建之前");
  },
  created() {
    // 在实例创建完成后被立即调用,此时可以访问data中的属性
    console.log("组件创建之后");
  },
  beforeMount() {
    // 在挂载开始之前被调用,相关的render函数首次被调用
    console.log("组件渲染之前");
  },
  mounted() {
    // el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子
    console.log("组件挂载之后");
  },
  beforeUpdate() {
    // 数据更新之前调用,可以访问data中的属性,但是视图尚未更新
    console.log("数据更新之前");
  },
  updated() {
    // 数据更新之后调用,可以访问data中的属性,视图已经更新
    console.log("数据更新之后");
  },
  beforeUnmount() {
    // 实例销毁之前调用,此时可以访问data中的属性,但是视图已经销毁
    console.log("组件卸载之前");
  },
  unmounted() {
    // 实例销毁后调用,此时不能访问data中的属性
    console.log("组件卸载之后");
  }
}
</script>
  • beforeCreate:在组件实例初始化之后调用,此时不能访问data中的属性。

  • created:在实例创建完成后被立即调用,此时可以访问data中的属性。

  • beforeMount:在挂载开始之前被调用,相关的render函数首次被调用。

  • mounted:el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。

  • beforeUpdate:数据更新之前调用,可以访问data中的属性,但是视图尚未更新。

  • updated:数据更新之后调用,可以访问data中的属性,视图已经更新。

  • beforeUnmount:实例销毁之前调用,此时可以访问data中的属性,但是视图已经销毁。

  • unmounted:实例销毁后调用,此时不能访问data中的属性。

生命周期应用

通过ref获取元素DOM结构

<template>
  <!-- 模板部分 -->
  <h3>组件生命周期应用</h3>
  <!-- 一个段落元素,通过ref属性设置引用名为"name" -->
  <p ref="name">哈哈哈</p>
</template>

<script>
export default {
  // beforeMount生命周期钩子
  beforeMount() {
    // 在这个阶段,DOM尚未渲染,因此$refs.name是undefined
    console.log(this.$refs.name); // 输出:undefined
  },
  // mounted生命周期钩子
  mounted() {
    // 在这个阶段,DOM已经渲染完成,可以通过$refs访问模板中的DOM元素
    console.log(this.$refs.name); // 输出:<p ref="name">哈哈哈</p>的DOM元素
  }
}
</script>
  • beforeMount 生命周期钩子:在这个阶段,Vue 已经完成了模板的编译,但是还没有挂载 DOM 元素,因此 this.$refs.nameundefined

  • mounted 生命周期钩子:在这个阶段,Vue 已经完成了模板的挂载,DOM 元素已经创建并添加到页面中,因此可以通过 this.$refs.name 访问到 <p> 元素的 DOM 对象。

模拟网络请求渲染数据,页面加载后初始化数据

<template>
  <!-- 模板部分 -->
  <h3>组件生命周期应用</h3>
  <!-- 使用v-for指令循环渲染banner数组中的每一项 -->
  <ul>
    <li v-for="(item, index) in banner" :key="index">
      <!-- 显示每一项的标题 -->
      <h3>{
  
  { item.title }}</h3>
      <!-- 显示每一项的内容 -->
      <p>{
  
  { item.content }}</p>
    </li>
  </ul>
</template>

<script>
export default {
  // data函数返回一个对象,其中包含一个banner数组,初始为空
  data() {
    return {
      banner: []
    }
  },
  // mounted生命周期钩子
  mounted() {
    // 在组件挂载到DOM后,初始化banner数组
    this.banner = [
      {
        "title": "我在爱尔兰",
        "content": "爱尔兰(爱尔兰语:Poblacht na hÉireann;英语:Republic of Ireland), 是一个西欧的议会共和制国家,西临大西洋,东靠爱尔兰海,与英国隔海相望,是北美通向欧洲的通道爱尔兰自然",
      },
      {
        "title": "一个人的东京",
        "content": "东京(Tokyo)是日本国的首都,是亚洲第一大城市,世界第二大城市。全球最大的经济中心之一。东京的著名观光景点有东京铁塔、皇居、国会议事堂、浅草寺、浜离宫、上野公园与动物园",
      },
      {
        "title": "普罗旺斯的梦",
        "content": "普罗旺斯(Provence)位于法国东南部,毗邻地中海和意大利,从地中海沿岸延伸到内陆的丘陵地区,中间有大河“Rhone”流过。自古就以靓丽的阳光和蔚蓝的天空,迷人的地中海和心醉",
      },
      {
        "title": "相约夏威夷之夏",
        "content": "夏威夷州位于北太平洋中,距离美国本土3,700公里,总面积16,633平方公里,属于太平洋沿岸地区。首府为檀香山。在1778至1898年间,夏威夷也被称为“三明治群岛”(Sandwich Islands)",
      }
    ]
  }
}
</script>

 23、动态组件

有些场景会需要在两个组件间来回切换,比如 Tab 界面

<template>
  <h3>ComponentA</h3>
</template>
<template>
  <h3>ComponentB</h3>
</template>
<template>
  <!-- 模板部分 -->
  <h3>组件切换</h3>
  <!-- 使用 :is 绑定来动态切换组件 -->
  <component :is="currentTab"></component>
  <!-- 一个按钮,点击时调用 changeComponentHandle 方法切换组件 -->
  <button @click="changeComponentHandle">切换</button>
</template>

<script>
// 导入ComponentA和ComponentB组件
import ComponentA from "./components/ComponentA.vue"
import ComponentB from "./components/ComponentB.vue"

export default {
  // 注册ComponentA和ComponentB为本地组件
  components: {
    ComponentA,
    ComponentB
  },
  // data函数返回一个对象,其中包含一个currentTab属性,用于控制显示哪个组件
  data() {
    return {
      currentTab: "ComponentA", // 默认显示ComponentA
    }
  },
  // methods对象包含组件的方法
  methods: {
    // changeComponentHandle方法用于切换currentTab的值,从而切换组件
    changeComponentHandle() {
      this.currentTab = this.currentTab === "ComponentA" ? "ComponentB" : "ComponentA";
    }
  }
}
</script>
  • :is 是一个属性绑定,它用于动态地绑定组件的名称或路径。

 就相当于是<componentA/>

24、组件保持存活

当使用 <component :is="..."> 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过<keep-alive>组件强制被切换掉的组件仍然保持“存活”的状态,下一次使用该组件的时候需要重新渲染,浪费资源。

就是加个标签的事儿

<template>
  <!-- 模板部分 -->
  <h3>组件切换</h3>
  <!-- 使用 <keep-alive> 包裹动态组件,保持切换组件的状态 -->
  <keep-alive>
    <!-- 使用 :is 绑定来动态切换组件 -->
    <!-- 当 currentTab 变化时,Vue 将根据 currentTab 的值渲染对应的组件 -->
    <component :is="currentTab"></component>
  </keep-alive>
  
  <!-- 一个按钮,点击时调用 changeComponentHandle 方法切换组件 -->
  <!-- 这将改变 currentTab 的值,从而触发组件的切换 -->
  <button @click="changeComponentHandle">切换</button>
</template>

<script>
// 导入ComponentA和ComponentB组件
import ComponentA from "./components/ComponentA.vue"
import ComponentB from "./components/ComponentB.vue"

export default {
  // 注册ComponentA和ComponentB为本地组件,使其在模板中可用
  components: {
    ComponentA,
    ComponentB
  },
  // data函数返回一个对象,其中包含一个currentTab属性,用于控制显示哪个组件
  data() {
    return {
      currentTab: "ComponentA", // 默认显示ComponentA组件
    }
  },
  // methods对象包含组件的方法
  methods: {
    // changeComponentHandle方法用于切换currentTab的值,从而切换组件
    // 当按钮被点击时,这个方法会被调用
    changeComponentHandle() {
      // 使用三元运算符来切换currentTab的值
      // 如果当前是ComponentA,则切换到ComponentB,反之亦然
      this.currentTab = this.currentTab === "ComponentA" ? "ComponentB" : "ComponentA";
    }
  }
}
</script>
  • <keep-alive> 标签用于包裹动态组件 <component :is="currentTab"></component>。它的作用是保持组件的状态,即使组件被切换,之前的状态也不会丢失,这样可以提高性能,因为避免了不必要的组件销毁和重建。

 25、异步组件

在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue 提供了 defineAsyncComponent方法来实现此功能

<template>
  <!-- 模板部分 -->
  <h3>组件切换</h3>
  <!-- 使用 <keep-alive> 包裹动态组件,保持切换组件的状态 -->
  <keep-alive>
    <!-- 使用 :is 绑定来动态切换组件 -->
    <!-- 当 currentTab 变化时,Vue 将根据 currentTab 的值渲染对应的组件 -->
    <component :is="currentTab"></component>
  </keep-alive>
  
  <!-- 一个按钮,点击时调用 changeComponentHandle 方法切换组件 -->
  <!-- 这将改变 currentTab 的值,从而触发组件的切换 -->
  <button @click="changeComponentHandle">切换</button>
</template>

<script>
// 从 'vue' 导入 defineAsyncComponent 方法,用于定义异步组件
import { defineAsyncComponent } from 'vue'
// 导入 ComponentA 组件
import ComponentA from "./components/ComponentA.vue"
// 使用 defineAsyncComponent 定义异步加载的 ComponentB 组件
const AsyncComponentB = defineAsyncComponent(() =>
  import('./components/ComponentB.vue')
)

export default {
  // 注册 ComponentA 和 AsyncComponentB 为本地组件,使其在模板中可用
  components: {
    ComponentA,
    AsyncComponentB
  },
  // data 函数返回一个对象,其中包含一个 currentTab 属性,用于控制显示哪个组件
  data() {
    return {
      currentTab: "ComponentA", // 默认显示 ComponentA 组件
    }
  },
  // methods 对象包含组件的方法
  methods: {
    // changeComponentHandle 方法用于切换 currentTab 的值,从而切换组件
    // 当按钮被点击时,这个方法会被调用
    changeComponentHandle() {
      // 使用条件运算符来切换 currentTab 的值
      // 如果当前是 ComponentA,则切换到 AsyncComponentB,反之亦然
      this.currentTab = this.currentTab == "ComponentA" ? "AsyncComponentB" : "ComponentA";
    }
  }
}
</script>
  1. 异步组件

    • 使用 defineAsyncComponent 方法定义了一个异步组件 AsyncComponentB。这允许 Vue 延迟加载 ComponentB.vue 文件,直到实际需要渲染该组件时才加载。

    • 异步组件在大型应用中非常有用,可以减少初始加载时间,提高性能。

26、依赖注入

通常情况下,当我们需要从父组件向子组件传递数据时,会使用 props。想象一下这样的结构:有一些多层级嵌套的组件,形成了一颗巨大的组件树,而某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦 。

这一问题被称为“prop 逐级透传”

provide 和 inject 可以帮助我们解决这一问题。 一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖 

<template>
  <!-- 模板部分 -->
  <h3>祖宗</h3> <!-- 显示“祖宗”标题 -->
  <Parent /> <!-- 使用子组件 Parent -->
</template>

<script>
// 导入子组件 Parent
import Parent from "./components/Parent.vue"

export default {
  // 使用 provide 提供一个 message,可以在子孙组件中通过 inject 访问
  provide: {
    message: "爷爷的财产"
  },
  // 注册子组件 Parent,使其在模板中可用
  components: {
    Parent
  }
}
</script>
<template>
  <!-- 模板部分 -->
  <h3>Parent</h3> <!-- 显示“Parent”标题 -->
  <Child /> <!-- 使用子组件 Child -->
</template>

<script>
// 导入子组件 Child
import Child from "./Child.vue"

export default {
  // 注册子组件 Child,使其在模板中可用
  components: {
    Child // 注册的组件名称与模板中使用的标签名称一致
  }
}
</script>

 

<template>
  <!-- 模板部分 -->
  <h3>Child</h3> <!-- 显示“Child”标题 -->
  <p>{
  
  { message }}</p> <!-- 显示从祖先组件注入的消息 -->
</template>

<script>
export default {
  // 使用 inject 选项来接收名为 message 的数据
  inject: ["message"]
}
</script>
  • provide/inject:这是 Vue 提供的一种跨组件通信方式,允许一个祖先组件向其所有子孙组件提供数据,而不必通过每个中间组件逐级传递 props。

  • provide 和 inject 只能由上到下的传递,不能反向传递

// 导入 Vue 的 createApp 函数
import { createApp } from 'vue'
// 导入根组件 App
import App from './App.vue'

// 创建一个 Vue 应用实例
const app = createApp(App)

// 使用 app.provide 提供全局数据
// 这里提供一个名为 "golabData" 的数据,值是 "我是全局数据"
app.provide("golabData", "我是全局数据")

// 将 Vue 应用挂载到 id 为 'app' 的 DOM 元素上
app.mount('#app')

 

  • 使用 app.provide("golabData", "我是全局数据") 提供一个全局数据。这里 golabData 是一个键,"我是全局数据" 是这个键对应的值。任何组件都可以通过 inject 选项访问这个全局数据。

 27、Vue应用

vue从哪开始执行的?

每个 Vue 应用都是通过 createApp函数创建一个新的 应用实例

// 从 'vue' 导入 createApp 函数,用于创建 Vue 应用实例
import { createApp } from 'vue'
// 导入根组件 App
import App from './App.vue'

// 创建 Vue 应用实例
// 在一个 Vue 项目中,通常只有一个 Vue 应用实例
const app = createApp(App)

// 将 Vue 应用挂载到页面中 id 为 'app' 的元素上
app.mount('#app')

我们传入 createApp 的对象实际上是一个组件,每个应用都需要一个“根组件”,其他组件将作为其子组件。

import { createApp } from 'vue'
// 从一个单文件组件中导入根组件
import App from './App.vue'


const app = createApp(App)

应用实例必须在调用了 .mount() 方法后才会渲染出来。该方法接收一个“容器”参数,可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串.页面挂载到index.html文件上的id=app元素上。

app.mount('#app')
<div id="app"></div>

src目录下的assets文件夹的作用就是存放公共资源,例如:图片、公共CSS或者字体图标等. 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2281576.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Git知识分享

一、理解git首先要理清楚下面五个概念&#xff1a; 1、工作区(git add 命令之前的样子) 2、stash 暂存(暂存工作区和暂存区的更改) 3、暂存区(git add 命令之后的存储区, 4、本地仓库(git commit提交的位置) 5、远程仓库(git push提交的位置) 二、git常用命令&#xff1a; 1、g…

【2024 - 年终总结】叶子增长,期待花开

写在前面&#xff1a;本博客仅作记录学习之用&#xff0c;部分图片来自网络&#xff0c;如需引用请注明出处&#xff0c;同时如有侵犯您的权益&#xff0c;请联系删除&#xff01; 文章目录 前言论博客创作保持2024的记录清单博客科研开源工作生活 总结与展望互动致谢参考 前言…

分类问题(二元,多元逻辑回归,费歇尔判别分析)spss实操

分类模型&#xff1a; 二分类和多分类&#xff1a; 对于二分类模型 &#xff0c;我们将介绍逻辑回归和Fisher线性判别分析两种分类算法; 对于多分类模型&#xff0c;我们将简单介绍Spss中的多分类线性判别分析和多分类逻辑回归的操作步骤 二分类: 基于广义线性模型&#x…

k8s使用nfs持久卷

开启持久化卷后可以实现服务开启在不同节点也能读取到和拿到服务节点的文件。 基本流程为将集群中一个节点作为服务节点安装共享储存应用的服务端选择目录和开启端口&#xff0c;其他节点根据端口挂载目录。然后使用kubesphere选择相应的镜像并将端口信息和挂载目录信息作为参…

kalman滤波器C++设计仿真案例

很多同学看了我之前的文章&#xff0c;都对kalman滤波器的原理有了理解&#xff0c;但我发现&#xff0c;在具体工程设计过程中&#xff0c;还是很多人都感觉到无从下手&#xff0c;一些参数也不知道如何选取。 这样吧。我这里举一些简单的例子&#xff0c;并用C来一步一步的进…

2025.1.21——六、BUU XSS COURSE 1 XSS漏洞|XSS平台搭建

题目来源&#xff1a;buuctf BUU XSS COURSE 1 目录 一、打开靶机&#xff0c;整理信息 二、解题思路 step 1&#xff1a;输入框尝试一下 step 2&#xff1a;开始xss注入 step 3&#xff1a;搭建平台 step 4&#xff1a;利用管理员cookie访问地址 三、小结 二编&#…

微信小程序使用上拉加载onReachBottom。页面拖不动。一直无法触发上拉的事件。

1&#xff0c;可能是原因是你使用了scroll-view的标签&#xff0c;用onReachBottom触发加载事件。这两个是有冲突的。没办法一起使用。如果页面的样式是滚动的是无法去触发页面的onReachBottom的函数的。因此&#xff0c;你使用overflow:auto.来使用页面的某些元素滚动&#xf…

Linux-arm(1)ATF启动流程

Linux-arm(1)ATF启动流量 Author&#xff1a;Once Day Date&#xff1a;2025年1月22日 漫漫长路有人对你微笑过嘛… 全系列文章可查看专栏: Linux实践记录_Once_day的博客-CSDN博客 参考文档&#xff1a; ARM Trusted Firmware分析——启动、PSCI、OP-TEE接口 Arnold Lu 博…

docker 部署 java 项目详解

在平常的开发工作中&#xff0c;我们经常需要部署项目&#xff0c;开发测试完成后&#xff0c;最关键的一步就是部署。今天我们以若依项目为例&#xff0c;总结下部署项目的整体流程。简单来说&#xff0c;第一步&#xff1a;安装项目所需的中间件&#xff1b;第二步&#xff1…

ARM64平台Flutter环境搭建

ARM64平台Flutter环境搭建 Flutter简介问题背景搭建步骤1. 安装ARM64 Android Studio2. 安装Oracle的JDK3. 安装 Dart和 Flutter 开发插件4. 安装 Android SDK5. 安装 Flutter SDK6. 同意 Android 条款7. 运行 Flutter 示例项目8. 修正 aapt2 报错9. 修正 CMake 报错10. 修正 N…

MySQL5.7安装超详细步骤(图文教程)

一.下载MySQL 1.在浏览器搜索MySQL&#xff0c;进入MySQL官网&#xff0c;点击下载&#xff0c;选下面的社区版本。 官网地址&#xff1a;MySQL :: Download MySQL Installer (Archived Versions) 二.安装MySQL 1.双击下载好的文件&#xff0c;选择自定义安装&#xff0c;然…

Tomcat下载配置

目录 Win下载安装 Mac下载安装配置 Win 下载 直接从官网下载https://tomcat.apache.org/download-10.cgi 在圈住的位置点击下载自己想要的版本 根据自己电脑下载64位或32位zip版本 安装 Tomcat是绿色版,直接解压到自己想放的位置即可 Mac 下载 官网 https://tomcat.ap…

语音转文字的先驱-认识Buzz的前世今生

Buzz 是一款基于 OpenAI Whisper 模型开发的开源语音转文字工具&#xff0c;其历史可以追溯到 Whisper 模型的推出&#xff0c;并在之后逐渐发展为一个功能强大且广泛使用的工具。以下是关于 Buzz 的详细历史介绍&#xff1a; 1. Whisper 模型的背景 Buzz 的核心是 OpenAI 开…

WPF5-x名称空间

1. x名称空间2. x名称空间内容3. x名称空间内容分类 3.1. x:Name3.2. x:Key3.3. x:Class3.4. x:TypeArguments 4. 总结 1. x名称空间 “x名称空间”的x是映射XAML名称空间时给它取的名字&#xff08;取XAML的首字母&#xff09;&#xff0c;里面的成员&#xff08;如x:Class、…

JavaWeb开发学习笔记——MySQL

跟着黑马程序员学习MySQLDay06-04. MySQL-DDL-数据库操作_哔哩哔哩_bilibili 注意&#xff0c;以下笔记中[ ]中都是可省略内容&#xff0c;如果不省略&#xff0c;那么直接写即可&#xff0c;不带[ ] MySQL-DDL 数据库操作 连接MySQL服务器&#xff1a;mysql -uroot -p密码…

CSS实现实现票据效果 mask与切图方式

一、“切图”的局限性 传统的“切图”简单暴力,但往往缺少适应性。 适应性一般有两种,一是尺寸自适应,二是颜色可以自定义。 举个例子,有这样一个优惠券样式 关于这类样式实现技巧,之前在这篇文章中有详细介绍: CSS 实现优惠券的技巧 不过这里略微不一样的地方是,两个…

【二叉树的深搜】二叉树剪枝

文章目录 814. 二叉树剪枝解题思路&#xff1a;深度优先遍历 后序遍历另一种写法 814. 二叉树剪枝 814. 二叉树剪枝 ​ 给你二叉树的根结点 root &#xff0c;此外树的每个结点的值要么是 0 &#xff0c;要么是 1 。 ​ 返回移除了所有不包含 1 的子树的原二叉树。 ​ 节点…

Codeforces Round 1000 (Div. 2) A-C

链接&#xff1a;Codeforces Round 1000 (Div. 2) A:Minimal Coprime 大意&#xff1a; 给定一个区间&#xff0c;定义最小互质区间是边界互质&#xff0c;边界内无互质区间。求这个区间最小互质区间个数 思路&#xff1a; gcd(l, l 1) gcd(1, l) 1,即相邻数组成的区间互…

基于Redis实现短信验证码登录

目录 1 基于Session实现短信验证码登录 2 配置登录拦截器 3 配置完拦截器还需将自定义拦截器添加到SpringMVC的拦截器列表中 才能生效 4 Session集群共享问题 5 基于Redis实现短信验证码登录 6 Hash 结构与 String 结构类型的比较 7 Redis替代Session需要考虑的问题 8 …

校验收货地址是否超出配送范围实战3(day09)

优化用户下单功能&#xff0c;加入校验逻辑&#xff0c;如果用户的收货地址距离商家门店超出配送范围&#xff08;配送范围为5公里内&#xff09;&#xff0c;则下单失败。 提示&#xff1a; ​ 1. 基于百度地图开放平台实现&#xff08;https://lbsyun.baidu.com/&#xff09…