首页 > 其他分享 >Vue 3 详解

Vue 3 详解

时间:2025-01-07 15:33:39浏览次数:3  
标签:Vue const vue 详解 组件 import ref

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

  1. Node 环境安装
    • Vue 3 的开发离不开 Node.js,它为项目提供了运行时环境与丰富的包管理能力。
  2. 开发编辑工具
    • Visual Studio Code(Vscode)是当下热门且功能强大的前端开发工具。
  3. 浏览器环境
    • 谷歌浏览器(Google Chrome)凭借出色的调试功能与对前端技术的良好支持,成为 Vue 开发的首选浏览器。

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

  1. 通过 CDN 使用 Vue
    • 在 HTML 文件中引入 Vue 3 的 CDN 链接,如:
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div id="app">{{ message }}</div>
<script type="module">
  import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  createApp({
    setup() {
      const message = ref('Hello Vue!')
      return {
        message
      }
    }
  }).mount('#app')
</script>
  • 这里先引入 Vue 全局脚本,然后利用 createApp 函数创建 Vue 应用实例,在 setup 函数中定义响应式数据 message,最后通过 .mount('#app') 将应用挂载到指定 DOM 节点(即 idappdiv)上,页面便能展示出 Hello Vue!
  • 还可以创建交互组件,如:
<div id="app">
  <button @click="count++">{{ count }}</button>
</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
createApp({
    setup() {
      const count = ref(0)
      return {
        count
      }
    }
  }).mount('#app')
</script>
  • 点击按钮,count 值会自动更新并在页面显示,展示了 Vue 的响应式特性。
  1. 通过 Vite 或者官方的命令行创建 Vue 3 项目
    • 使用 Vite:
      • 首先确保已安装 Node.js,在终端执行 npm init vite@latest my-vue3-app -- --template vuemy-vue3-app 为项目名称,可自定义),这会创建一个基于 Vue 3 和 Vite 的初始项目结构。
      • 进入项目目录 cd my-vue3-app,执行 npm install 安装依赖,然后 npm run dev 启动开发服务器,即可在浏览器访问 http://localhost:3000 查看初始页面,后续可在此基础上进行组件开发、路由配置等操作。
    • 使用官方命令行工具(需先全局安装 @vue/clinpm install -g @vue/cli):
      • 执行 vue create my-vue3-projectmy-vue3-project 为自定义项目名),按提示选择 Vue 3 相关预设,如默认配置或手动选择功能插件(如路由、状态管理等),完成项目创建。同样进入项目目录后 npm run serve 启动开发服务器,开启开发流程。

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

  1. 模板语法
    • 文本插值:使用双大括号 {{}},如 <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 攻击,谨慎使用。
  2. 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>
  3. 响应式原理
    • ref():通过 ref 函数创建响应式数据,如 const count = ref(0),在 JavaScript 中访问其值需使用 .value,即 count.value,但在模板中使用时无需加 .value,Vue 会自动处理。当 count.value 发生变化,使用该数据的 DOM 区域会自动更新。
    • DOM 更新时机:Vue 采用异步更新策略,修改响应式状态时,DOM 不会立即更新,而是在“next tick”更新周期中缓冲所有状态修改,确保每个组件只更新一次。若需等待 DOM 更新完成后执行额外代码,可使用 nextTick 全局 API,如:
    import { nextTick } from 'vue'
    async function increment() {
      count.value++
      await nextTick()
      // 现在 DOM 已经更新了
    }
    
    • 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>
    import { ref } from "vue";
    const list = ref({
      books: [
        "语文",
        "数学",
        "英语",
      ],
    });
    </script>
    <template>
      <p>是否拥有书籍:</p>
      <span>{{ list.books.length > 0? "Yes" : "No" }}</span>
    </template>
    
    • 但这样会使模板逻辑复杂,不易维护。
    • 有计算属性:使用 computed 函数创建计算属性,如:
    <script setup>
    import { ref, computed } from "vue";
    const list = ref({
      books: [
        "语文",
        "数学",
        "英语",
      ],
    });
    // 一个计算属性 ref
    const booksLength = computed(() => {
      return list.value.books.length > 0? "Yes" : "No";
    });
    </script>
    <template>
      <p>拥有书籍的个数:</p>
      <span>{{ booksLength }}</span>
    </template>
    
    • 计算属性会基于其依赖的数据自动缓存结果,当依赖数据不变时,不会重复计算,提升性能,且在模板中使用如同普通数据,简洁清晰。
    • 可写计算属性
    <script setup>
    import { ref, computed } from "vue";
    const firstName = ref("老");
    const lastName = ref("王");
    const fullName = computed({
      // getter
      get() {
        return firstName.value + " " + lastName.value;
      },
      // setter
      set(newValue) {
        // 注意:我们这里使用的是解构赋值语法
        [firstName.value, lastName.value] = newValue.split(" ");
      },
    });
    // fullName.value = "范 冰冰";
    </script>
    <template>
      <p>Has published books:</p>
      <span>{{ fullName }}</span>
    </template>
    
    • 通过定义 getset 方法,既能像普通属性读取,又能在赋值时执行自定义逻辑,实现数据双向关联。
  2. 类与样式绑定

    • 类绑定
      • 绑定 HTML class:使用 :class 指令,可绑定对象或计算属性,如:
    <script setup>
    import { ref, computed } from "vue";
    const isActive = ref(true);
    const isTitle = ref(true);
    const computedClass = computed(() => ({ active: isActive, title: isTitle }));
    </script>
    <template>
      <div :class="computedClass">drogen</div>
    </template>
    
    • 绑定数组:可传递数组元素作为类名,如:
    <script setup>
    import { ref } from "vue";
    const active = ref("active");
    const title = ref("title");
    const isActive = ref(true);
    </script>
    <template>
      <div :class="[isActive? active : '', title]">drogen</div>
    </template>
    
    • 绑定内联样式:使用 :style 指令,可绑定对象,对象属性为 CSS 样式名与对应值,如:
    <script setup>
    import { ref } from "vue";
    const color = ref("red");
    const fontSize = ref(40);
    const styleObject = ref({
      color: "red",
      fontSize: "40px",
      });
    </script>
    <template>
      <div :style="styleObject">drogen</div>
    </template>
    
  3. 条件渲染与列表渲染

    • 条件渲染
      • v-if+v-else:根据条件决定元素是否渲染,如:
    <script setup>
    import { ref } from "vue";
    const title = ref(true);
    </script>
    <template>
      <h1 v-if="title">drogen</h1>
      <h2 v-else>chenxuyuan.net</h2>
    </template>
    
    • v-else-if:实现多条件分支,如:
    <script setup>
    import { ref } from "vue";
    const type = ref(1);
    </script>
    <template>
      <h1 v-if="type === 1">drogen</h1>
      <h2 v-else-if="type === 2">html</h2>
      <h2 v-else-if="type === 3">css</h2>
      <h2 v-else-if="type === 4">js</h2>
      <h2 v-else>chenxuyuan.net</h2>
    </template>
    
      - `v-show`:元素始终渲染,通过 `display` 属性控制显示隐藏,如:
    
    <script setup>
    import { ref } from "vue";
    const title = ref(true);
    </script>
    <template>
      <h1 v-show="title">drogen</h1>
    </template>
    
    • 列表渲染
      • v-for:遍历数组或对象,如:
    <script setup>
    import { ref } from "vue";
    const courseList = ref(["html", "css", "js"]);
    </script>
    <template>
      <ul>
        <li v-for="item in courseList">{{ item }}</li>
      </ul>
    </template>
    
    • 也可使用 of 关键字,如 <li v-for="item of courseList">{{ item }}</li>,效果相同。
    • 嵌套遍历:
    <script setup>
    import { ref } from "vue";
    const courseList = ref([
      { name: "html", list: ["h1", "h2", "h3"] },
      { name: "css", list: ["color", "fontSize", "display"] },
      { name: "js", list: ["var", "const", "let"] },
    ]);
    </script>
    <template>
      <ul>
        <li v-for="item in courseList">
          {{ item.name }}
          <div v-for="childItem in item.list">{{ childItem }}</div>
        </li>
      </ul>
    </template>
    
    • 注意:不推荐 v-ifv-for 同时用在同一标签,因为 v-if 优先级高于 v-for,会导致 v-if 条件无法访问 v-for 作用域内变量别名,如:
    <script setup>
    import { ref } from "vue";
    const courseObject = ref({ front: "js", back: "java" });
    </script>
    <template>
      <ul>
        <li v-for="(value, key, index) in courseObject" v-if="!value">
          {{ value }} - {{ key }} -{{ index }}
        </li>
      </ul>
    </template>
    
  4. 事件处理与表单输入绑定

    • 事件处理
      • 监听事件:使用 v-on:click 或简写 @click,如:
    <script setup>
    import { ref } from "vue";
    const count = ref(0);
    const addClick = () => {
      count.value++;
    };
    </script>
    <template>
      <div @click="addClick()">计数器:{{ count }}</div>
    </template>
    
    • 事件修饰符:如 .stop 阻止冒泡、.prevent 阻止默认行为、.self 仅当事件目标是自身时触发、.capture 使用捕获模式、.once 只触发一次、.passive 提升移动端滚动性能;按键修饰符如 .enter.tab 等用于特定按键监听,系统按键修饰符 .ctrl.alt 等可组合使用。
    • 表单输入绑定
      • 未使用 Vue 时,需手动处理双向数据绑定,如:
    <input
      :value="text"
      @input="event => text = event.target.value"
    >
    
    • 使用 v-model 指令简化,如:
    <input v-model="text">
    
    • 不同表单元素用法:
      • 文本
    <p>Message is: {{ message }}</p>
    <input v-model="message" placeholder="edit me" />
    
    - **复选框**:
    
    <input type="checkbox" id="checkbox" v-model="checked" />
    <label for="checkbox">{{ checked }}</label>
    
        - **单选按钮**:
    
    <div>Picked: {{ picked }}</div>
    <input type="radio" id="one" value="One" v-model="picked" />
    <label for="one">One</label>
    <input type="radio" id="two" value="Two" v-model="picked" />
    <label for="two">Two</label>
    
    - **选择器**:
    
    <div>Selected: {{ selected }}</div>
    <select v-model="selected">
      <option disabled value="">Please select one</option>
      <option>A</option>
      <option>B</option>
      <option>C</option>
    </select>
    
  5. 侦听器

    • 使用 watch 侦听器:
    <script setup>
    import { ref, watch } from 'vue';
    
    const question = ref('');
    const answer = ref('答案');
    const loading = ref(false);
    
    // 可以直接侦听一个 ref
    watch(question, (newQuestion) => {
      if (newQuestion.includes('?')) {
        loading.value = true;
        answer.value = 'Thinking...';
        setTimeout(() => {
          answer.value = '是的';
        }, 1000);
      }
    });
    </script>
    
    <template>
      <p>
        提问问题
        <input v-model="question" :disabled="loading" />
      </p>
      <p>{{ answer }}</p>
    </template>
    
    • 这里侦听 question 数据变化,当输入包含 ? 时,更新 loadinganswer 状态模拟异步获取答案过程。
    • 侦听数据源类型
      • 可侦听 ref(包括计算属性)、响应式对象、getter 函数、多个数据源组成的数组。注意不能直接侦听响应式对象的属性值,需通过 getter 函数,如:
    const obj = ref({ count: 0 });
    // 错误,因为 watch() 得到的参数是一个 number
    watch(obj.value, (count) => {
      console.log(`count is: ${count}`);
    });
    // 提供一个 getter 函数
    watch(
      () => obj.value.count,
      (count) => {
        console.log(`count is: ${count}`);
      }
    );
    
    • 深层侦听器
      • 侦听响应式对象:
    const obj = ref({ count: 0 });
    watch(obj.value, (newValue, oldValue) => {
      // 在嵌套的属性变更时触发
      // 注意:`newValue` 此处和 `oldValue` 是相等的
      // 因为它们是同一个对象!
    });
    obj.count++;
    
    • 侦听返回响应式对象的 getter 函数(开销大,慎用):
    watch(
      () => state.someObject,
      (newValue, oldValue) => {
        // 注意:`newValue` 此处和 `oldValue` 是相等的
        // *除非* state.someObject 被整个替换了
      },
      { deep: true }
    );
    
    • 即时回调侦听器
    watch(
      source,
      (newValue, oldValue) => {
        // 立即执行,且当 `source` 改变时再次执行
      },
      { immediate: true }
    );
    
    • 一次性侦听器
    watch(
      source,
      (newValue, oldValue) => {
        // 当 `source` 变化时,仅触发一次
      },
      { once: true }
    );
    
    • watchEffect():会在副作用发生期间追踪依赖,自动追踪所有能访问到的响应式属性,代码简洁但响应性依赖关系有时不明确,如:
    import { ref } from 'vue';
    const count = ref(0);
    WatchEffect(() => {
      console.log(`当前 count 的值为 ${count.value}`);
    });
    
  6. 模板引用

    • 模板引用 ref
    <script setup>
    import { ref, onMounted } from 'vue';
    
    // 声明一个 ref 来存放该元素的引用
    // 必须和模板里的 ref 同名
    const input = ref(null);
    
    onMounted(() => {
      input.value.focus();
    });
    </script>
    
    <template>
      <input ref="input" />
    </template>
    
    • 这里获取输入框元素引用,在组件挂载后使其获取焦点。
    • 函数的模板引用
    <input :ref="(el) => { /* 将 el 赋值给一个数据属性或 ref 变量 */ }">
    
    • v-for 模板引用
    <script setup>
    import { ref, onMounted } from 'vue';
    
    const list = ref([
      /*... */
    ]);
    
    const itemRefs = ref([]);
    
    onMounted(() => console.log(itemRefs.value));
    </script>
    
    <template>
      <ul>
        <li v-for="item in list" ref="itemRefs">
          {{ item }}
        </li>
      </ul>
    </template>
    
    • 组件上的 ref
    <script setup>
    import { ref, onMounted } from 'vue';
    import Child from './Child.vue';
    
    const child = ref(null);
    
    onMounted(() => {
      // child.value 是 <Child /> 组件的实例
    });
    </script>
    
    <template>
      <Child ref="child" />
    </template>
    

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

  1. 认识 Vue 3 当中的生命周期函数
    <script setup>
    import { ref, onMounted } from 'vue';
      
    const data = ref('');
      
    // 挂载时机生命周期函数;
    onMounted(() => {
      setTimeout(() => {
        data.value = 'drogen';
      }, 100);
    });
    </script>
      
    <template>
      <div>接口 100ms 后请求数据:</div>
      <span>{{ data }}</span>
    </template>
    
    • 这里利用 onMounted 在组件挂载完成后,通过定时器模拟异步请求数据并更新 data 展示。
    • onMounted:常用于执行定时器、绑定事件、订阅消息等操作,此时组件已挂载到 DOM,可访问真实 DOM 元素。
    • onUnMounted:组件卸载之后,用于清除定时器、取消订阅消息等,防止内存泄漏。
  2. 概览 Vue 3 的所有生命周期函数流程
    • 组件生命周期图示清晰展示各阶段,从初始化开始,历经挂载、更新、卸载等环节,各阶段有对应的生命周期函数被调用。
  3. 详解生命周期的初始化流程:组件加载前进行基础数据初始化等操作,为后续挂载做准备。
  4. 详解生命周期的挂载流程
    • onBeforeMount:在组件即将挂载到 DOM 之前被调用,模板已编译完成但未渲染,可在此预处理数据。
    • onMounted:组件挂载到 DOM 后立即调用,常用于 DOM 操作。
  5. 详解生命周期的更新 + 销毁流程
    • onBeforeUpdate:组件数据更新前调用,可保存状态等。
    • onUpdated:数据更新并重新渲染完成后调用,可检查更新后的 DOM。
    • onBeforeUnmount:组件即将卸载前调用,清理资源。
    • onUnmounted:组件从 DOM 中卸载后调用,标志生命周期结束。

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

  1. Vue 3 单页面组件开发基础 - 组件定义 + 使用
    • 组件定义
    <script setup>
    import { ref } from 'vue';
    
    const count = ref(0);
    </script>
    
    <template>
      <button @click="count++">You clicked me {{ count }} times.</button>
    </template>
    
    • 定义一个简单的按钮点击计数组件。
    • 使用组件
    <script setup>
    import ButtonCounter from './ButtonCounter.vue';
    </script>
    
    <template>
      <h1>Here is a child component!</h1>
      <ButtonCounter />
    </template>
    
    • 在父组件中导入并使用子组件,可多次重用。
    • 闭合写法:使用自定义标签名调用组件,如 <button-counter></button-counter>,需在父组件正确注册。
    • 传递 props
    <script setup>
    defineProps(['title']);
    </script>
    
    <template>
      <h4>{{ title }}</h4>
    </template>
    
    - 在子组件通过 `defineProps` 接收父组件传入属性,父组件使用时:
    
    <ChildComponent title="drogen" />
    
  2. Vue 3 单页面组件开发基础 - 监听事件
    • 父组件传递函数给子组件:
      • $emit + defineEmits
        • 子组件:
    defineEmits(["childClick"]);
    @click="$emit('childClick')"
    
        - 父组件:
         ```html
         @childClick="()=>{}"
         ```	
    
    • 传递参数
      • 子组件:
      defineEmits(["childClick"]);
      @click="$emit('childClick','chenxuyuan.net')"
      
      • 父组件:
      @childClick="(n)=>{console.log(n)}"
      
    • 还可在子组件通过 emit 函数触发:
      <script setup>
      import { ref } from 'vue';
      const emit = defineEmits(["childClick"]);
      
      onMounted(() => {
        emit("childClick", "声明式触发事件");
      });
      </script>
      
  3. Vue 3 单页面组件开发基础 - 插槽
    • defineExpose
      • 子组件:
    <script setup>
    const cxy = ref(0);
    defineExpose({ cxy });
    </script>
    
    • 父组件:
    <script setup>
    const childRef = ref('');
    <child-component ref='childRef' />
    <span>{{ childRef.cxy }}<span/>
    </script>
    
    • 插槽 slot
      • 子组件:
    <template>
      <slot></slot>
    </template>
    
    • 父组件:
    <child-component>
      drogen
    </<child-component>
    

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

  1. Vue 3 单页面组件开发进阶 - 组件注册 + 命名
    • 组件注册
      • 全局注册
    // main.js
    import { createApp } from 'vue';
    import App from './App.vue';
    import ChildComponent from './ChildComponent.vue';
    
    const app = createApp(App);
    app.component('ChildComponent', ChildComponent);
    app.mount('#app');
    
    • 全局注册虽方便,但存在问题:不必要的文件体积,未使用组件无法 tree - shaking;难维护,依赖关系不明确。
    • 局部注册:在使用组件的父组件中通过 import 导入并在 components 选项注册,更利于大型项目维护。
    • 组件名格式:推荐大驼峰(ChildComponent)或连字符格式(child-component),遵循统一规范利于代码可读性与维护性。
  2. Vue 3 单页面组件开发进阶 - props
    • props 声明
    <script setup>
    const props = defineProps(['cxy']);
    
    console.log(props.cxy);
    </script>
    <script setup>
    defineProps({
      cxy: String,
      name: String
    });
    </script>
    
    • 通过 defineProps 声明接收父组件传入属性,指定类型利于开发时错误排查。
    • props 名字格式:建议小驼峰命名,符合 JavaScript 变量命名习惯。
    • 静态和动态
      • 静态:<ChildComponent title="drogen" />
      • 动态:<ChildComponent :title="cxy" />,通过 : 绑定动态数据。
    • 单项数据流
      • prop 是只读的,不能直接修改,如:
    const props = defineProps(['cxy']);
    // ❌ 警告!prop 是只读的!
    props.cxy = 'chenxuyuan.net';
    
    • 更改用法:
      • 用于初始值:
    const props = defineProps(['cxy']);
    // 计数器只是将 props.cxy 作为初始值
    // 像下面这样做就使 prop 和后续更新无关了
    const counter = ref(props.cxy);
    
    - 进一步处理/转换:
    
    const props = defineProps(['cxy']);
    // 该 prop 变更时计算属性也会自动更新
    const newcxy = computed(() => props.cxy + '老王');
    
  3. Vue 3 单页面组件开发进阶 - defineModel
    • 实现父子组件数据双向绑定的新语法糖:
      • 子组件:
    <script setup>
    const model = defineModel();
    </script>
    
    <template>
      <h2>子组件</h2>
      <input v-model="model" />
    </template>
    
    • 父组件:
    <script setup>
    import ChildComponent from "./ChildComponent.vue";
    import { ref } from "vue";
    
    const cxy = ref("drogen");
    </script>
    
    <template>
      <h1>父组件</h1>
      <span>{{ cxy }}</span>
      <ChildComponent v-model="cxy"></ChildComponent>
    </script>
    
    • 还可多属性双向绑定:
      • 父组件:
      <ChildComponent v-model:cxy="cxy" v-model:aa="aa"></ChildComponent>
      
      • 子组件:
      const cxy = defineModel("cxy");
      const aa = defineModel("aa");
      
      <input type="text" v-model="cxy" />
      <input type="text" v-model="aa" />
      
  4. Vue 3 单页面组件开发进阶 - 依赖注入
    • 依赖注入:用于跨组件层级传递数据,无需层层传递 props
    • provide + inject
      • 供给方组件:
        <script setup>
        import { provide } from 'vue';
        
        provide(/* 注入名 */ 'message', /* 值 */ 'hello!');
        </script>
        
      • 注入方组件:
        <script setup>
        import { inject } from 'vue';
        
        const message = inject('message');
        </script>
        
      • 和响应式数据配合:
        • 供给方组件:
        <script setup>
        import { provide, ref } from 'vue';
        
        const cxy = ref('drogen');
        
        function updatecxy() {
          cxy.value = 'chenxuyuan.net';
        }
        
        provide('cxy', {
          cxy,
          updatecxy
        });
        </script>
        
        • 注入方组件:
        <script setup>
        import { inject } from 'vue';
        
        const { cxy, updatecxy } = inject('cxy');
        </script>
        
        <template>
          <button @click="updatecxy">{{ cxy }}</button>
        </template>
        
    • 注意:注入的数据默认只读,防止意外修改导致数据混乱。
  5. Vue 3 单页面组件开发进阶 - KeepAlive
    • 是内置组件,用于在多个组件间动态切换时缓存被移除的组件实例:
    <script setup>
    import ChildComponent1 from "./ChildComponent1.vue";
    import ChildComponent2 from "./ChildComponent2.vue";
    import { ref } from "vue";
    const cxy = ref(true);
    </script>
    <template>
      <h1>父组件</h1>
      <button @click="() => (cxy =!cxy)">切换组件</button>
      <KeepAlive><ChildComponent1 v-if="cxy" /></KeepAlive>
      <ChildComponent2 v-if="!cxy" />
    </template>
    
    • 如切换回缓存组件,其状态(如计数器值)保持不变,提升用户体验。

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

  1. Vue 3 单页面实现规模化 Vue Router 基础 - 入门使用

    • 安装:执行 pnpm install vue-router@4 安装 Vue Router 4。
    • 使用
    import { createRouter, createWebHashHistory } from 'vue-router';
    
    import ChildComponent1 from './ChildComponent1.vue';
    import ChildComponent2 from './ChildComponent2.vue';
    const routes = [
      { path: '/one', component: ChildComponent1 },
      { path: '/two', component: ChildComponent2 },
    ];
    const router = createRouter({
      history: createWebHashHistory(),
      routes,
    });
    
    export default router;
    
    <script setup>
    import { ref } from 'vue';
    
    const cxy = ref(true);
    </script>
    <template>
      <h1>父组件</h1>
      <p>
        <!-- 通过传递 `to` 来指定链接 -->
        <router-link to="/one">去组件1</router-link> <br />
        <router-link to="/two">去组件2</router-link>
      </p>
      <div>
        <!-- 路由出口 -->
        <router-view></router-view>
      </div>
    </template>
    
    • 这里创建路由实例,定义路由路径与对应组件,在父组件通过 <router-link> 实现导航链接,<router-view> 展示当前路由匹配组件内容。
  2. Vue 3 单页面实现规模化 Vue Router 基础 - 嵌套路由 + 编程式导航

    • 嵌套路由
    import { createRouter, createWebHashHistory } from 'vue-router';
    import ChildComponent1 from './ChildComponent1.vue';
    import ChildComponent2 from './ChildComponent2.vue';
    import ChildComponent3 from './ChildComponent3.vue';
    
    const routes = [
      {
        path: '/one',
        component: ChildComponent1,
      },
      {
        path: '/two',
    'two',
        component: ChildComponent2,
        children: [
          {
            path: 'aa',
            component: ChildComponent3,
          },
        ],
      },
    ];
    
    const router = createRouter({
      history: createWebHashHistory(),
      routes,
    });
    
    export default router;
    
    • 上述代码定义了嵌套路由,当访问 /two/aa 时,会在 ChildComponent2<router-view> 子路由出口中展示 ChildComponent3 组件,实现更复杂的页面布局与导航结构。
    • 编程式导航
    <script setup>
    import router from "./router.js";
    const routerChange = (n) => {
      router.push(n);
    };
    </script>
    <template>
      <h1>父组件</h1>
      <p>
        <button @click="routerChange('/one')">打开组件1</button> <br />
        <button @click="routerChange('/two')">打开组件2</button><br />
        <button @click="routerChange('/two/aa')">打开组件3</button>
      </p>
      <div>
        <router-view></router-view>
      </div>
    </template>
    
    • 通过 router.push 方法实现编程式导航,可在 JavaScript 代码中根据业务逻辑灵活切换路由,比如点击按钮时触发相应路由跳转。
  3. Vue 3 单页面实现规模化 Vue Router 基础 - 命名 + 重定向

    import { createRouter, createWebHashHistory } from 'vue-router';
    import ChildComponent1 from './ChildComponent1.vue';
    import ChildComponent2 from './ChildComponent2.vue';
    import ChildComponent3 from './ChildComponent3.vue';
    
    const routes = [
      {
        path: '/',
        redirect: '/one',
      },
      {
        path: '/one',
        name: 'one',
        component: ChildComponent1,
      },
      {
        path: '/two',
        name: 'two',
        component: ChildComponent2,
        children: [
          {
            path: 'three',
            name: 'three',
            component: ChildComponent3,
          },
        ],
      },
    ];
    
    const router = createRouter({
      history: createWebHashHistory(),
      routes,
    });
    
    export default router;
    
    • 为路由命名方便后续编程式导航引用,如 router.push({ name: 'one' }) 。设置重定向可在用户访问根路径 "/" 时自动跳转到指定路由,优化用户初始访问体验。
  4. Vue 3 单页面实现规模化 Vue Router 基础 - 路由传参

    • query
    <router-link
      :to="{ path: '/one', query: { cxy: 'drogen', state: 'chenxuyuan' } }"
      >打开组件1</router-link
    >
    
    • 通过 query 参数传递数据,在目标组件可通过 $route.query 获取,如 this.$route.query.cxy ,常用于携带一些非关键、临时性的搜索条件等信息,参数会显示在 URL 中。
    • params
    <router-link :to="{ name: 'one', params: { cxy: 'drogen' } }"
      >打开组件1</router-link
    >
    path: "/one/:cxy"
    
    • 先在路由定义中声明参数占位符 :cxy ,然后通过 params 传递,在目标组件通过 $route.params 获取,参数不会显示在 URL 中,适合传递一些敏感或对 URL 美观有要求的数据,如用户 ID 等。
    • 编程式导航传参
    const routerChange = (n, obj) => {
      router.push({ path: n, query: obj });
    };
    
    • 以编程方式跳转路由并传参,灵活实现业务逻辑中的数据传递需求。
  5. Vue 3 单页面实现规模化 Vue Router 进阶 - 历史记录模式 + 导航守卫

    • 不同的历史记录模式
      • 哈希模式:createWebHashHistory() ,此模式 URL 带有 # 符号,如 http://localhost:3000/#/one ,兼容性好,服务器无需特殊配置,是推荐的入门模式。
      • html5 模式:createWebHistory() ,使用 HTML5 History API,URL 更简洁美观,如 http://localhost:3000/one ,但需要服务器配合进行 URL 重写,防止刷新页面出现 404 错误。
    • 导航守卫
    router.beforeEach((to, from, next) => {
      if (to.meta.isAuth) {
        if (localStorage.getItem("token") === "1") {
          next();
        } else {
          alert("请先登录");
        }
      } else {
        next();
      }
    });
    
    • 在路由跳转前进行权限验证等操作,to 是即将进入的目标路由,from 是当前离开的路由,next 用于控制导航流程,决定是否继续跳转、重定向或中断导航,保障应用安全性与业务逻辑正确性。
  6. Vue 3 单页面实现规模化 Vue Router 进阶 - 路由懒加载

    component: () => import("./ChildComponent1.vue"),
    
    • 采用路由懒加载技术,将组件的加载延迟到路由被访问时,而非一次性加载所有组件,优化初始加载性能,尤其在大型项目中有大量组件时,能显著减少初始包体积,加快页面首次加载速度,提升用户体验。

标签:Vue,const,vue,详解,组件,import,ref
From: https://blog.csdn.net/Founder_Xiao_Xin/article/details/144984200

相关文章

  • React函数组件中与生命周期相关Hooks详解
    React函数组件及其钩子渲染流程是React框架中的核心概念之一。以下是对该流程的详细解析:一、React函数组件基础定义:React函数组件是一个接收props作为参数并返回React元素的函数。它们通常用于表示UI的一部分,并且不保留内部状态(除非使用React的Hooks)。......
  • 卡尔曼滤波(Kalman Filter) 从理论到实战详解 附算法源码
    目录一、卡尔曼滤波的引入二、状态观测器三、最优状态估计四、最优状态估计算法和方程五、热成像仪使用卡尔曼滤波器案例一、卡尔曼滤波的引入卡尔曼滤波用于优化估算我们感兴趣的量,当这些量无法直接测量但可以间接测量的时候,他们还用于估算系统状态,通过组合各种可能......
  • 前端VUE首次加载错误类型
    今天我们就把所有前端VUE首次加载错误类型统一算一遍!:语法错误模板语法错误:在Vue的模板中使用了不正确的语法。如在插值表达式中少了花括号,或使用了错误的指令语法等。例如,{{message(少了一个花括号),或v-ifmessage="true"(少了冒号)。JavaScript语法错误:在Vue组件的脚本部......
  • Django SimpleUI 配置详解:SIMPLEUI_CONFIG 和常用图标
    DjangoSimpleUI是一个优秀的Django管理界面美化工具,通过简单的配置,就能让你的管理后台焕然一新。本文将详细介绍SIMPLEUI_CONFIG的配置选项以及常用的图标,帮助你打造一个美观实用的管理界面。1.SIMPLEUI_CONFIG配置详解SIMPLEUI_CONFIG是django-simpleui库的核......
  • Linux(Centos 7.6)命令详解:rmdir
    1.命令作用如果目录为空,则删除该目录(RemovetheDIRECTORY(ies),iftheyareempty)2.命令语法Usage:rmdir[OPTION]...DIRECTORY...3.参数详解OPTION:--ignore-fail-on-non-empty,忽略每个因为目录为非空的错误(如果目录非空,不会报错也不会删除非空目录)-p,--parent......
  • 前端学习openLayers配合vue3(加载矢量图标)
    今天我们来进行矢量图标的加载关键代码有一个比较注意的点就是,图片路径必须引入不能直接写路径,我找半天也没发现问题所在letanchorLayer=newVectorLayer({source:newVectorSource(),});letanchorFeatures=newFeature({geometry:newPoint(cen......
  • 【AJAX详解】
    AJAX详解AJAX(AsynchronousJavaScriptandXML)是一种创建交互式网页应用的网页开发技术。它允许在不重新加载整个页面的情况下,通过后台与服务器交换数据并更新部分网页内容。这提供了更流畅的用户体验,因为用户不需要等待整个页面刷新来获取新的信息。AJAX的核心概念异步......
  • I/O 多路复用,网络编程中的select、poll、epoll的发展历史、原理详解以及代码实现(四)
    上节基于select实现了一个简单的TCP回显服务器的应用,它通过创建并监听服务器套接字,以及使用select对文件描述符进行监控(接受客户端的连接,并监听是否有可读事件),最后通过recv和send函数实现数据接受以及数据回发。本节将在上节的基础上,使用poll替代select,但仍保持TCP回显服务器......
  • I/O 多路复用,网络编程中的select、poll、epoll的发展历史、原理详解以及代码实现(三)
    上节讲到select、poll、epoll的原理详解,本节将对三者的代码实现进行介绍,此外,为了方便读者更好地对其使用场景进行理解,本节还将基于三者实现一个简单的tcp回显服务器的应用(EchoServer)。1.创建tcp回显服务器(1)创建服务器套接字intsockfd=socket(AF_INET,SOCK_STREAM,0);......
  • I/O 多路复用,网络编程中的select、poll、epoll的发展历史、原理详解以及代码实现(二)
    select、poll和epoll是Linux中实现I/O多路复用的三种主要方法,它们的设计思想和实现原理各有不同,用于满足不同的场景需求。上一节介绍了他们三者的发展历史,本节我将继续介绍他们三者的详细原理。(PS:本系列文章面向的读者群体需要有一定的基本网络编程知识,若文章中出现的一......