Vue 3 详解

打印 上一主题 下一主题

主题 1016|帖子 1016|积分 3048

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
一、开辟环境搭建:基石奠定


  • Node 环境安装

    • Vue 3 的开辟离不开 Node.js,它为项目提供了运行时环境与丰富的包管理能力。

  • 开辟编辑工具

    • Visual Studio Code(Vscode)是当下热门且功能强大的前端开辟工具。

  • 浏览器环境

    • 谷歌浏览器(Google Chrome)依附出色的调试功能与对前端技术的良好支持,成为 Vue 开辟的首选浏览器。

二、初窥 Vue 3:创建首个应用


  • 通过 CDN 使用 Vue

    • 在 HTML 文件中引入 Vue 3 的 CDN 链接,如:

  1. <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  2. <div id="app">{{ message }}</div>
  3. <script type="module">
  4.   import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  5.   createApp({
  6.     setup() {
  7.       const message = ref('Hello Vue!')
  8.       return {
  9.         message
  10.       }
  11.     }
  12.   }).mount('#app')
  13. </script>
复制代码


  • 这里先引入 Vue 全局脚本,然后使用 createApp 函数创建 Vue 应用实例,在 setup 函数中定义相应式数据 message,末了通过 .mount('#app') 将应用挂载到指定 DOM 节点(即 id 为 app 的 div)上,页面便能展示出 Hello Vue!。
  • 还可以创建交互组件,如:
  1. <div id="app">
  2.   <button @click="count++">{{ count }}</button>
  3. </div>
  4. <script type="module">
  5. import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  6. createApp({
  7.     setup() {
  8.       const count = ref(0)
  9.       return {
  10.         count
  11.       }
  12.     }
  13.   }).mount('#app')
  14. </script>
复制代码


  • 点击按钮,count 值会自动更新并在页面表现,展示了 Vue 的相应式特性。

  • 通过 Vite 或者官方的命令行创建 Vue 3 项目

    • 使用 Vite:

      • 首先确保已安装 Node.js,在终端实行 npm init vite@latest my-vue3-app -- --template vue(my-vue3-app 为项目名称,可自定义),这会创建一个基于 Vue 3 和 Vite 的初始项目布局。
      • 进入项目目录 cd my-vue3-app,实行 npm install 安装依赖,然后 npm run dev 启动开辟服务器,即可在浏览器访问 http://localhost:3000 检察初始页面,后续可在此底子上进行组件开辟、路由配置等操纵。

    • 使用官方命令行工具(需先全局安装 @vue/cli:npm install -g @vue/cli):

      • 实行 vue create my-vue3-project(my-vue3-project 为自定义项目名),按提示选择 Vue 3 相关预设,如默认配置或手动选择功能插件(如路由、状态管理等),完成项目创建。同样进入项目目录后 npm run serve 启动开辟服务器,开启开辟流程。


三、核心知识剖析:语法与特性


  • 模板语法

    • 文本插值:使用双大括号 {{}},如 <span>Message: {{ msg }}</span>,msg 为 Vue 实例中的相应式数据,能及时将数据渲染到页面。
    • 插入 HTML

      • 插值语法插入 HTML 字符串时,会以文本情势表现,如 <p>插值语法插入html: {{ <span style="color: red">drogen</span> }}</p>,只会表现 HTML 代码文本。
      • 若要正确渲染 HTML,需使用 v-html 指令,如 <p>v-html指令: <span v-html="rawHtml"></span></p>,此中 rawHtml 应为包罗合法 HTML 标签的字符串变量,要注意制止 XSS 攻击,审慎使用。


  • Attribute 绑定

    • 使用 v-bind 指令,可简写为 :,如 <div v-bind:id="cxy"></div> 或 <div :id="cxy"></div>,cxy 为 Vue 实例中的数据,能动态绑定元素属性。常用于按钮禁用状态绑定 <button :disabled="isDisabled"> 按钮 </button>,或链接跳转地点绑定 <a :href="https://chenxuyuan.net"> drogen官网 </a>。

  • 相应式原理

    • ref():通过 ref 函数创建相应式数据,如 const count = ref(0),在 JavaScript 中访问其值需使用 .value,即 count.value,但在模板中使用时无需加 .value,Vue 会自动处理惩罚。当 count.value 发生变化,使用该数据的 DOM 地区会自动更新。
    • DOM 更新时机:Vue 采用异步更新策略,修改相应式状态时,DOM 不会立刻更新,而是在“next tick”更新周期中缓冲全部状态修改,确保每个组件只更新一次。若需等待 DOM 更新完成后实行额外代码,可使用 nextTick 全局 API,如:
    1. import { nextTick } from 'vue'
    2. async function increment() {
    3.   count.value++
    4.   await nextTick()
    5.   // 现在 DOM 已经更新了
    6. }
    复制代码
      

    • reactive():用于创建相应式对象,如 const state = reactive({ count: 0 }),但它有一定局限性:

      • 只能用于对象范例(对象、数组和如 Map、Set 这样的集合范例),不能持有如 string、number 或 boolean 这样的原始范例。
      • 不能替换整个对象,否则相应性连接将丢失,如 state = reactive({ count: 1 }) 会导致原 state 的相应性失效。
      • 对解构操纵不友好,解构后的数据与原相应式对象断开连接,如 const { count } = state,修改 count 不会影响原 state.count,若要保持相应性,需传入整个对象。


四、进阶特性:提拔开辟效能


  • 盘算属性

    • 无盘算属性:在模板中直接进行复杂逻辑运算,如:
    1. <script setup>
    2. import { ref } from "vue";
    3. const list = ref({
    4.   books: [
    5.     "语文",
    6.     "数学",
    7.     "英语",
    8.   ],
    9. });
    10. </script>
    11. <template>
    12.   <p>是否拥有书籍:</p>
    13.   <span>{{ list.books.length > 0? "Yes" : "No" }}</span>
    14. </template>
    复制代码
      

    • 但这样会使模板逻辑复杂,不易维护。
    • 有盘算属性:使用 computed 函数创建盘算属性,如:
    1. <script setup>
    2. import { ref, computed } from "vue";
    3. const list = ref({
    4.   books: [
    5.     "语文",
    6.     "数学",
    7.     "英语",
    8.   ],
    9. });
    10. // 一个计算属性 ref
    11. const booksLength = computed(() => {
    12.   return list.value.books.length > 0? "Yes" : "No";
    13. });
    14. </script>
    15. <template>
    16.   <p>拥有书籍的个数:</p>
    17.   <span>{{ booksLength }}</span>
    18. </template>
    复制代码
      

    • 盘算属性会基于其依赖的数据自动缓存结果,当依赖数据稳固时,不会重复盘算,提拔性能,且在模板中使用如同平凡数据,简洁清楚。
    • 可写盘算属性
    1. <script setup>
    2. import { ref, computed } from "vue";
    3. const firstName = ref("老");
    4. const lastName = ref("王");
    5. const fullName = computed({
    6.   // getter
    7.   get() {
    8.     return firstName.value + " " + lastName.value;
    9.   },
    10.   // setter
    11.   set(newValue) {
    12.     // 注意:我们这里使用的是解构赋值语法
    13.     [firstName.value, lastName.value] = newValue.split(" ");
    14.   },
    15. });
    16. // fullName.value = "范 冰冰";
    17. </script>
    18. <template>
    19.   <p>Has published books:</p>
    20.   <span>{{ fullName }}</span>
    21. </template>
    复制代码
      

    • 通过定义 get 和 set 方法,既能像平凡属性读取,又能在赋值时实行自定义逻辑,实现数据双向关联。

  • 类与样式绑定

    • 类绑定

      • 绑定 HTML class:使用 :class 指令,可绑定对象或盘算属性,如:

    1. <script setup>
    2. import { ref, computed } from "vue";
    3. const isActive = ref(true);
    4. const isTitle = ref(true);
    5. const computedClass = computed(() => ({ active: isActive, title: isTitle }));
    6. </script>
    7. <template>
    8.   <div :class="computedClass">drogen</div>
    9. </template>
    复制代码
      

    • 绑定数组:可传递数组元素作为类名,如:
    1. <script setup>
    2. import { ref } from "vue";
    3. const active = ref("active");
    4. const title = ref("title");
    5. const isActive = ref(true);
    6. </script>
    7. <template>
    8.   <div :class="[isActive? active : '', title]">drogen</div>
    9. </template>
    复制代码
      

    • 绑定内联样式:使用 :style 指令,可绑定对象,对象属性为 CSS 样式名与对应值,如:
    1. <script setup>
    2. import { ref } from "vue";
    3. const color = ref("red");
    4. const fontSize = ref(40);
    5. const styleObject = ref({
    6.   color: "red",
    7.   fontSize: "40px",
    8.   });
    9. </script>
    10. <template>
    11.   <div :style="styleObject">drogen</div>
    12. </template>
    复制代码

  • 条件渲染与列表渲染

    • 条件渲染

      • v-if+v-else:根据条件决定元素是否渲染,如:

    1. <script setup>
    2. import { ref } from "vue";
    3. const title = ref(true);
    4. </script>
    5. <template>
    6.   <h1 v-if="title">drogen</h1>
    7.   <h2 v-else>chenxuyuan.net</h2>
    8. </template>
    复制代码
      

    • v-else-if:实现多条件分支,如:
    1. <script setup>
    2. import { ref } from "vue";
    3. const type = ref(1);
    4. </script>
    5. <template>
    6.   <h1 v-if="type === 1">drogen</h1>
    7.   <h2 v-else-if="type === 2">html</h2>
    8.   <h2 v-else-if="type === 3">css</h2>
    9.   <h2 v-else-if="type === 4">js</h2>
    10.   <h2 v-else>chenxuyuan.net</h2>
    11. </template>
    复制代码
    1.   - `v-show`:元素始终渲染,通过 `display` 属性控制显示隐藏,如:
    复制代码
    1. <script setup>
    2. import { ref } from "vue";
    3. const title = ref(true);
    4. </script>
    5. <template>
    6.   <h1 v-show="title">drogen</h1>
    7. </template>
    复制代码
      

    • 列表渲染

      • v-for:遍历数组或对象,如:

    1. <script setup>
    2. import { ref } from "vue";
    3. const courseList = ref(["html", "css", "js"]);
    4. </script>
    5. <template>
    6.   <ul>
    7.     <li v-for="item in courseList">{{ item }}</li>
    8.   </ul>
    9. </template>
    复制代码
      

    • 也可使用 of 关键字,如 <li v-for="item of courseList">{{ item }}</li>,结果类似。
    • 嵌套遍历:
    1. <script setup>
    2. import { ref } from "vue";
    3. const courseList = ref([
    4.   { name: "html", list: ["h1", "h2", "h3"] },
    5.   { name: "css", list: ["color", "fontSize", "display"] },
    6.   { name: "js", list: ["var", "const", "let"] },
    7. ]);
    8. </script>
    9. <template>
    10.   <ul>
    11.     <li v-for="item in courseList">
    12.       {{ item.name }}
    13.       <div v-for="childItem in item.list">{{ childItem }}</div>
    14.     </li>
    15.   </ul>
    16. </template>
    复制代码
      

    • 注意:不保举 v-if 和 v-for 同时用在同一标签,因为 v-if 优先级高于 v-for,会导致 v-if 条件无法访问 v-for 作用域内变量别名,如:
    1. <script setup>
    2. import { ref } from "vue";
    3. const courseObject = ref({ front: "js", back: "java" });
    4. </script>
    5. <template>
    6.   <ul>
    7.     <li v-for="(value, key, index) in courseObject" v-if="!value">
    8.       {{ value }} - {{ key }} -{{ index }}
    9.     </li>
    10.   </ul>
    11. </template>
    复制代码

  • 事件处理惩罚与表单输入绑定

    • 事件处理惩罚

      • 监听事件:使用 v-on:click 或简写 @click,如:

    1. <script setup>
    2. import { ref } from "vue";
    3. const count = ref(0);
    4. const addClick = () => {
    5.   count.value++;
    6. };
    7. </script>
    8. <template>
    9.   <div @click="addClick()">计数器:{{ count }}</div>
    10. </template>
    复制代码
      

    • 事件修饰符:如 .stop 阻止冒泡、.prevent 阻止默认活动、.self 仅当事件目标是自身时触发、.capture 使用捕获模式、.once 只触发一次、.passive 提拔移动端滚动性能;按键修饰符如 .enter、.tab 等用于特定按键监听,体系按键修饰符 .ctrl、.alt 等可组合使用。
    • 表单输入绑定

      • 未使用 Vue 时,需手动处理惩罚双向数据绑定,如:

    1. <input
    2.   :value="text"
    3.   @input="event => text = event.target.value"
    4. >
    复制代码
      

    • 使用 v-model 指令简化,如:
    1. <input v-model="text">
    复制代码
      

    • 不同表单元素用法:

      • 文本

    1. <p>Message is: {{ message }}</p>
    2. <input v-model="message" placeholder="edit me" />
    复制代码
    1. - **复选框**:
    复制代码
    1. <input type="checkbox" id="checkbox" v-model="checked" />
    2. <label for="checkbox">{{ checked }}</label>
    复制代码
    1.     - **单选按钮**:
    复制代码
    1. <div>Picked: {{ picked }}</div>
    2. <input type="radio" id="one" value="One" v-model="picked" />
    3. <label for="one">One</label>
    4. <input type="radio" id="two" value="Two" v-model="picked" />
    5. <label for="two">Two</label>
    复制代码
    1. - **选择器**:
    复制代码
    1. <div>Selected: {{ selected }}</div>
    2. <select v-model="selected">
    3.   <option disabled value="">Please select one</option>
    4.   <option>A</option>
    5.   <option>B</option>
    6.   <option>C</option>
    7. </select>
    复制代码

  • 侦听器

    • 使用 watch 侦听器:
    1. <script setup>
    2. import { ref, watch } from 'vue';
    3. const question = ref('');
    4. const answer = ref('答案');
    5. const loading = ref(false);
    6. // 可以直接侦听一个 ref
    7. watch(question, (newQuestion) => {
    8.   if (newQuestion.includes('?')) {
    9.     loading.value = true;
    10.     answer.value = 'Thinking...';
    11.     setTimeout(() => {
    12.       answer.value = '是的';
    13.     }, 1000);
    14.   }
    15. });
    16. </script>
    17. <template>
    18.   <p>
    19.     提问问题
    20.     <input v-model="question" :disabled="loading" />
    21.   </p>
    22.   <p>{{ answer }}</p>
    23. </template>
    复制代码
      

    • 这里侦听 question 数据变化,当输入包罗 ? 时,更新 loading 和 answer 状态模拟异步获取答案过程。
    • 侦听数据源范例

      • 可侦听 ref(包括盘算属性)、相应式对象、getter 函数、多个数据源构成的数组。注意不能直接侦听相应式对象的属性值,需通过 getter 函数,如:

    1. const obj = ref({ count: 0 });
    2. // 错误,因为 watch() 得到的参数是一个 number
    3. watch(obj.value, (count) => {
    4.   console.log(`count is: ${count}`);
    5. });
    6. // 提供一个 getter 函数
    7. watch(
    8.   () => obj.value.count,
    9.   (count) => {
    10.     console.log(`count is: ${count}`);
    11.   }
    12. );
    复制代码
      

    • 深层侦听器

      • 侦听相应式对象:

    1. const obj = ref({ count: 0 });
    2. watch(obj.value, (newValue, oldValue) => {
    3.   // 在嵌套的属性变更时触发
    4.   // 注意:`newValue` 此处和 `oldValue` 是相等的
    5.   // 因为它们是同一个对象!
    6. });
    7. obj.count++;
    复制代码
      

    • 侦听返反相应式对象的 getter 函数(开销大,慎用):
    1. watch(
    2.   () => state.someObject,
    3.   (newValue, oldValue) => {
    4.     // 注意:`newValue` 此处和 `oldValue` 是相等的
    5.     // *除非* state.someObject 被整个替换了
    6.   },
    7.   { deep: true }
    8. );
    复制代码
      

    • 即时回调侦听器
    1. watch(
    2.   source,
    3.   (newValue, oldValue) => {
    4.     // 立即执行,且当 `source` 改变时再次执行
    5.   },
    6.   { immediate: true }
    7. );
    复制代码
      

    • 一次性侦听器
    1. watch(
    2.   source,
    3.   (newValue, oldValue) => {
    4.     // 当 `source` 变化时,仅触发一次
    5.   },
    6.   { once: true }
    7. );
    复制代码
      

    • watchEffect():会在副作用发生期间追踪依赖,自动追踪全部能访问到的相应式属性,代码简洁但相应性依赖关系有时不明确,如:
    1. import { ref } from 'vue';
    2. const count = ref(0);
    3. WatchEffect(() => {
    4.   console.log(`当前 count 的值为 ${count.value}`);
    5. });
    复制代码

  • 模板引用

    • 模板引用 ref
    1. <script setup>
    2. import { ref, onMounted } from 'vue';
    3. // 声明一个 ref 来存放该元素的引用
    4. // 必须和模板里的 ref 同名
    5. const input = ref(null);
    6. onMounted(() => {
    7.   input.value.focus();
    8. });
    9. </script>
    10. <template>
    11.   <input ref="input" />
    12. </template>
    复制代码
      

    • 这里获取输入框元素引用,在组件挂载后使其获取焦点。
    • 函数的模板引用
    1. <input :ref="(el) => { /* 将 el 赋值给一个数据属性或 ref 变量 */ }">
    复制代码
      

    • v-for 模板引用
    1. <script setup>
    2. import { ref, onMounted } from 'vue';
    3. const list = ref([
    4.   /*... */
    5. ]);
    6. const itemRefs = ref([]);
    7. onMounted(() => console.log(itemRefs.value));
    8. </script>
    9. <template>
    10.   <ul>
    11.     <li v-for="item in list" ref="itemRefs">
    12.       {{ item }}
    13.     </li>
    14.   </ul>
    15. </template>
    复制代码
      

    • 组件上的 ref
    1. <script setup>
    2. import { ref, onMounted } from 'vue';
    3. import Child from './Child.vue';
    4. const child = ref(null);
    5. onMounted(() => {
    6.   // child.value 是 <Child /> 组件的实例
    7. });
    8. </script>
    9. <template>
    10.   <Child ref="child" />
    11. </template>
    复制代码

五、生命周期:组件的生命轨迹


  • 认识 Vue 3 当中的生命周期函数
    1. <script setup>
    2. import { ref, onMounted } from 'vue';
    3.   
    4. const data = ref('');
    5.   
    6. // 挂载时机生命周期函数;
    7. onMounted(() => {
    8.   setTimeout(() => {
    9.     data.value = 'drogen';
    10.   }, 100);
    11. });
    12. </script>
    13.   
    14. <template>
    15.   <div>接口 100ms 后请求数据:</div>
    16.   <span>{{ data }}</span>
    17. </template>
    复制代码

    • 这里使用 onMounted 在组件挂载完成后,通过定时器模拟异步请求数据并更新 data 展示。
    • onMounted:常用于实行定时器、绑定事件、订阅消息等操纵,此时组件已挂载到 DOM,可访问真实 DOM 元素。
    • onUnMounted:组件卸载之后,用于扫除定时器、取消订阅消息等,防止内存走漏。

  • 概览 Vue 3 的全部生命周期函数流程

    • 组件生命周期图示清楚展示各阶段,从初始化开始,历经挂载、更新、卸载等环节,各阶段有对应的生命周期函数被调用。

  • 详解生命周期的初始化流程:组件加载前进行底子数据初始化等操纵,为后续挂载做准备。
  • 详解生命周期的挂载流程

    • onBeforeMount:在组件即将挂载到 DOM 之前被调用,模板已编译完成但未渲染,可在此预处理惩罚数据。
    • onMounted:组件挂载到 DOM 后立刻调用,常用于 DOM 操纵。

  • 详解生命周期的更新 + 烧毁流程

    • onBeforeUpdate:组件数据更新前调用,可保存状态等。
    • onUpdated:数据更新并重新渲染完成后调用,可查抄更新后的 DOM。
    • onBeforeUnmount:组件即将卸载前调用,清算资源。
    • onUnmounted:组件从 DOM 中卸载后调用,标记生命周期结束。

六、组件开辟:构建 Vue 应用基石


  • Vue 3 单页面组件开辟底子 - 组件定义 + 使用

    • 组件定义
    1. <script setup>
    2. import { ref } from 'vue';
    3. const count = ref(0);
    4. </script>
    5. <template>
    6.   <button @click="count++">You clicked me {{ count }} times.</button>
    7. </template>
    复制代码
      

    • 定义一个简朴的按钮点击计数组件。
    • 使用组件
    1. <script setup>
    2. import ButtonCounter from './ButtonCounter.vue';
    3. </script>
    4. <template>
    5.   <h1>Here is a child component!</h1>
    6.   <ButtonCounter />
    7. </template>
    复制代码
      

    • 在父组件中导入并使用子组件,可多次重用。
    • 闭合写法:使用自定义标署名调用组件,如 <button-counter></button-counter>,需在父组件正确注册。
    • 传递 props
    1. <script setup>
    2. defineProps(['title']);
    3. </script>
    4. <template>
    5.   <h4>{{ title }}</h4>
    6. </template>
    7. - 在子组件通过 `defineProps` 接收父组件传入属性,父组件使用时:
    8. <ChildComponent title="drogen" />
    复制代码

  • Vue 3 单页面组件开辟底子 - 监听事件

    • 父组件传递函数给子组件:

      • $emit + defineEmits

        • 子组件:


    1. defineEmits(["childClick"]);
    2. @click="$emit('childClick')"
    复制代码
    1.     - 父组件:
    2.      ```html
    3.      @childClick="()=>{}"
    4.      ```       
    复制代码
      

    • 传递参数

      • 子组件:
      1. defineEmits(["childClick"]);
      2. @click="$emit('childClick','chenxuyuan.net')"
      复制代码
         

      • 父组件:
      1. @childClick="(n)=>{console.log(n)}"
      复制代码

    • 还可在子组件通过 emit 函数触发:
      1. <script setup>
      2. import { ref } from 'vue';
      3. const emit = defineEmits(["childClick"]);
      4. onMounted(() => {
      5.   emit("childClick", "声明式触发事件");
      6. });
      7. </script>
      复制代码

  • Vue 3 单页面组件开辟底子 - 插槽

    • defineExpose

      • 子组件:

    1. <script setup>
    2. const cxy = ref(0);
    3. defineExpose({ cxy });
    4. </script>
    复制代码
      

    • 父组件:
    1. <script setup>
    2. const childRef = ref('');
    3. <child-component ref='childRef' />
    4. <span>{{ childRef.cxy }}<span/>
    5. </script>
    复制代码
      

    • 插槽 slot

      • 子组件:

    1. <template>
    2.   <slot></slot>
    3. </template>
    复制代码
      

    • 父组件:
    1. <child-component>
    2.   drogen
    3. </<child-component>
    复制代码

七、组件进阶:优化与拓展组件功能


  • Vue 3 单页面组件开辟进阶 - 组件注册 + 定名

    • 组件注册

      • 全局注册

    1. // main.js
    2. import { createApp } from 'vue';
    3. import App from './App.vue';
    4. import ChildComponent from './ChildComponent.vue';
    5. const app = createApp(App);
    6. app.component('ChildComponent', ChildComponent);
    7. app.mount('#app');
    复制代码
      

    • 全局注册虽方便,但存在题目:不必要的文件体积,未使用组件无法 tree - shaking;难维护,依赖关系不明确。
    • 局部注册:在使用组件的父组件中通过 import 导入并在 components 选项注册,更利于大型项目维护。
    • 组件名格式:保举大驼峰(ChildComponent)或连字符格式(child-component),遵照同一规范利于代码可读性与维护性。

  • Vue 3 单页面组件开辟进阶 - props

    • props 声明
    1. <script setup>
    2. const props = defineProps(['cxy']);
    3. console.log(props.cxy);
    4. </script>
    5. <script setup>
    6. defineProps({
    7.   cxy: String,
    8.   name: String
    9. });
    10. </script>
    复制代码
      

    • 通过 defineProps 声明接收父组件传入属性,指定范例利于开辟时错误排查。
    • props 名字格式:建议小驼峰定名,符合 JavaScript 变量定名风俗。
    • 静态和动态

      • 静态:<ChildComponent title="drogen" />。
      • 动态:<ChildComponent :title="cxy" />,通过 : 绑定动态数据。

    • 单项数据流

      • prop 是只读的,不能直接修改,如:

    1. const props = defineProps(['cxy']);
    2. // ❌ 警告!prop 是只读的!
    3. props.cxy = 'chenxuyuan.net';
    复制代码
      

    • 更改用法:

      • 用于初始值:

    1. const props = defineProps(['cxy']);
    2. // 计数器只是将 props.cxy 作为初始值
    3. // 像下面这样做就使 prop 和后续更新无关了
    4. const counter = ref(props.cxy);
    复制代码
    1. - 进一步处理/转换:
    复制代码
    1. const props = defineProps(['cxy']);
    2. // 该 prop 变更时计算属性也会自动更新
    3. const newcxy = computed(() => props.cxy + '老王');
    复制代码

  • Vue 3 单页面组件开辟进阶 - defineModel

    • 实现父子组件数据双向绑定的新语法糖:

      • 子组件:

    1. <script setup>
    2. const model = defineModel();
    3. </script>
    4. <template>
    5.   <h2>子组件</h2>
    6.   <input v-model="model" />
    7. </template>
    复制代码
      

    • 父组件:
    1. <script setup>
    2. import ChildComponent from "./ChildComponent.vue";
    3. import { ref } from "vue";
    4. const cxy = ref("drogen");
    5. </script>
    6. <template>
    7.   <h1>父组件</h1>
    8.   <span>{{ cxy }}</span>
    9.   <ChildComponent v-model="cxy"></ChildComponent>
    10. </script>
    复制代码
      

    • 还可多属性双向绑定:

      • 父组件:
      1. <ChildComponent v-model:cxy="cxy" v-model:aa="aa"></ChildComponent>
      复制代码
         

      • 子组件:
      1. const cxy = defineModel("cxy");
      2. const aa = defineModel("aa");
      3. <input type="text" v-model="cxy" />
      4. <input type="text" v-model="aa" />
      复制代码


  • Vue 3 单页面组件开辟进阶 - 依赖注入

    • 依赖注入:用于跨组件层级传递数据,无需层层传递 props。
    • provide + inject

      • 供给方组件:
        1. <script setup>
        2. import { provide } from 'vue';
        3. provide(/* 注入名 */ 'message', /* 值 */ 'hello!');
        4. </script>
        复制代码
      • 注入方组件:
        1. <script setup>
        2. import { inject } from 'vue';
        3. const message = inject('message');
        4. </script>
        复制代码
      • 和相应式数据共同:

        • 供给方组件:
        1. <script setup>
        2. import { provide, ref } from 'vue';
        3. const cxy = ref('drogen');
        4. function updatecxy() {
        5.   cxy.value = 'chenxuyuan.net';
        6. }
        7. provide('cxy', {
        8.   cxy,
        9.   updatecxy
        10. });
        11. </script>
        复制代码
              

        • 注入方组件:
        1. <script setup>
        2. import { inject } from 'vue';
        3. const { cxy, updatecxy } = inject('cxy');
        4. </script>
        5. <template>
        6.   <button @click="updatecxy">{{ cxy }}</button>
        7. </template>
        复制代码


    • 注意:注入的数据默认只读,防止不测修改导致数据紊乱。

  • Vue 3 单页面组件开辟进阶 - KeepAlive

    • 是内置组件,用于在多个组件间动态切换时缓存被移除的组件实例:
    1. <script setup>
    2. import ChildComponent1 from "./ChildComponent1.vue";
    3. import ChildComponent2 from "./ChildComponent2.vue";
    4. import { ref } from "vue";
    5. const cxy = ref(true);
    6. </script>
    7. <template>
    8.   <h1>父组件</h1>
    9.   <button @click="() => (cxy =!cxy)">切换组件</button>
    10.   <KeepAlive><ChildComponent1 v-if="cxy" /></KeepAlive>
    11.   <ChildComponent2 v-if="!cxy" />
    12. </template>
    复制代码
      

    • 如切换回缓存组件,其状态(如计数器值)保持稳固,提拔用户体验。

八、路由应用:构建单页面应用导航


  • Vue 3 单页面实现规模化 Vue Router 底子 - 入门使用

    • 安装:实行 pnpm install vue-router@4 安装 Vue Router 4。
    • 使用
    1. import { createRouter, createWebHashHistory } from 'vue-router';
    2. import ChildComponent1 from './ChildComponent1.vue';
    3. import ChildComponent2 from './ChildComponent2.vue';
    4. const routes = [
    5.   { path: '/one', component: ChildComponent1 },
    6.   { path: '/two', component: ChildComponent2 },
    7. ];
    8. const router = createRouter({
    9.   history: createWebHashHistory(),
    10.   routes,
    11. });
    12. export default router;
    复制代码
    1. <script setup>
    2. import { ref } from 'vue';
    3. const cxy = ref(true);
    4. </script>
    5. <template>
    6.   <h1>父组件</h1>
    7.   <p>
    8.     <!-- 通过传递 `to` 来指定链接 -->
    9.     <router-link to="/one">去组件1</router-link> <br />
    10.     <router-link to="/two">去组件2</router-link>
    11.   </p>
    12.   <div>
    13.     <!-- 路由出口 -->
    14.     <router-view></router-view>
    15.   </div>
    16. </template>
    复制代码
      

    • 这里创建路由实例,定义路由路径与对应组件,在父组件通过 <router-link> 实现导航链接,<router-view> 展示当前路由匹配组件内容。

  • Vue 3 单页面实现规模化 Vue Router 底子 - 嵌套路由 + 编程式导航

    • 嵌套路由
    1. import { createRouter, createWebHashHistory } from 'vue-router';
    2. import ChildComponent1 from './ChildComponent1.vue';
    3. import ChildComponent2 from './ChildComponent2.vue';
    4. import ChildComponent3 from './ChildComponent3.vue';
    5. const routes = [
    6.   {
    7.     path: '/one',
    8.     component: ChildComponent1,
    9.   },
    10.   {
    11.     path: '/two',
    12. 'two',
    13.     component: ChildComponent2,
    14.     children: [
    15.       {
    16.         path: 'aa',
    17.         component: ChildComponent3,
    18.       },
    19.     ],
    20.   },
    21. ];
    22. const router = createRouter({
    23.   history: createWebHashHistory(),
    24.   routes,
    25. });
    26. export default router;
    复制代码
      

    • 上述代码定义了嵌套路由,当访问 /two/aa 时,会在 ChildComponent2 的 <router-view> 子路由出口中展示 ChildComponent3 组件,实现更复杂的页面布局与导航布局。
    • 编程式导航
    1. <script setup>
    2. import router from "./router.js";
    3. const routerChange = (n) => {
    4.   router.push(n);
    5. };
    6. </script>
    7. <template>
    8.   <h1>父组件</h1>
    9.   <p>
    10.     <button @click="routerChange('/one')">打开组件1</button> <br />
    11.     <button @click="routerChange('/two')">打开组件2</button><br />
    12.     <button @click="routerChange('/two/aa')">打开组件3</button>
    13.   </p>
    14.   <div>
    15.     <router-view></router-view>
    16.   </div>
    17. </template>
    复制代码
      

    • 通过 router.push 方法实现编程式导航,可在 JavaScript 代码中根据业务逻辑灵活切换路由,好比点击按钮时触发相应路由跳转。

  • Vue 3 单页面实现规模化 Vue Router 底子 - 定名 + 重定向
    1. import { createRouter, createWebHashHistory } from 'vue-router';
    2. import ChildComponent1 from './ChildComponent1.vue';
    3. import ChildComponent2 from './ChildComponent2.vue';
    4. import ChildComponent3 from './ChildComponent3.vue';
    5. const routes = [
    6.   {
    7.     path: '/',
    8.     redirect: '/one',
    9.   },
    10.   {
    11.     path: '/one',
    12.     name: 'one',
    13.     component: ChildComponent1,
    14.   },
    15.   {
    16.     path: '/two',
    17.     name: 'two',
    18.     component: ChildComponent2,
    19.     children: [
    20.       {
    21.         path: 'three',
    22.         name: 'three',
    23.         component: ChildComponent3,
    24.       },
    25.     ],
    26.   },
    27. ];
    28. const router = createRouter({
    29.   history: createWebHashHistory(),
    30.   routes,
    31. });
    32. export default router;
    复制代码

    • 为路由定名方便后续编程式导航引用,如 router.push({ name: 'one' }) 。设置重定向可在用户访问根路径 "/" 时自动跳转到指定路由,优化用户初始访问体验。

  • Vue 3 单页面实现规模化 Vue Router 底子 - 路由传参

    • query
    1. <router-link
    2.   :to="{ path: '/one', query: { cxy: 'drogen', state: 'chenxuyuan' } }"
    3.   >打开组件1</router-link
    4. >
    复制代码
      

    • 通过 query 参数传递数据,在目标组件可通过 $route.query 获取,如 this.$route.query.cxy ,常用于携带一些非关键、临时性的搜索条件等信息,参数会表现在 URL 中。
    • params
    1. <router-link :to="{ name: 'one', params: { cxy: 'drogen' } }"
    2.   >打开组件1</router-link
    3. >
    4. path: "/one/:cxy"
    复制代码
      

    • 先在路由定义中声明参数占位符 :cxy ,然后通过 params 传递,在目标组件通过 $route.params 获取,参数不会表现在 URL 中,适合传递一些敏感或对 URL 美观有要求的数据,如用户 ID 等。
    • 编程式导航传参
    1. const routerChange = (n, obj) => {
    2.   router.push({ path: n, query: obj });
    3. };
    复制代码
      

    • 以编程方式跳转路由并传参,灵活实现业务逻辑中的数据传递需求。

  • Vue 3 单页面实现规模化 Vue Router 进阶 - 汗青记载模式 + 导航守卫

    • 不同的汗青记载模式

      • 哈希模式:createWebHashHistory() ,此模式 URL 带有 # 符号,如 http://localhost:3000/#/one ,兼容性好,服务器无需特别配置,是保举的入门模式。
      • html5 模式:createWebHistory() ,使用 HTML5 History API,URL 更简洁美观,如 http://localhost:3000/one ,但需要服务器共同进行 URL 重写,防止革新页面出现 404 错误。

    • 导航守卫
    1. router.beforeEach((to, from, next) => {
    2.   if (to.meta.isAuth) {
    3.     if (localStorage.getItem("token") === "1") {
    4.       next();
    5.     } else {
    6.       alert("请先登录");
    7.     }
    8.   } else {
    9.     next();
    10.   }
    11. });
    复制代码
      

    • 在路由跳转前进行权限验证等操纵,to 是即将进入的目标路由,from 是当前脱离的路由,next 用于控制导航流程,决定是否继续跳转、重定向或停止导航,保障应用安全性与业务逻辑正确性。

  • Vue 3 单页面实现规模化 Vue Router 进阶 - 路由懒加载
    1. component: () => import("./ChildComponent1.vue"),
    复制代码

    • 采用路由懒加载技术,将组件的加载延迟到路由被访问时,而非一次性加载全部组件,优化初始加载性能,尤其在大型项目中有大量组件时,能明显减少初始包体积,加快页面初次加载速率,提拔用户体验。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表