Vue3笔记

0 阅读7分钟

建立vue项目

npm init vue@latest

Need to install the following packages:
create-vue@3.10.3 Ok to proceed? (y) y
Vue.js - The Progressive JavaScript Framework
√ 请输入项目名称: ... vue-base
√ 是否使用 TypeScript 语法? ... 否 / 是
√ 是否启用 JSX 支持? ... 否 / 是
√ 是否引入 Vue Router 进行单页面应用开发? ... 否 / 是
√ 是否引入 Pinia 用于状态管理? ... 否 / 是
√ 是否引入 Vitest 用于单元测试? ... 否 / 是
√ 是否要引入一款端到端(End to End)测试工具?
√ 是否引入 ESLint 用于代码质量检测? ... 否 / 是
√ 是否引入 Vue DevTools 7 扩展用于调试? (试验阶段) ... 否 / 是
正在初始化项目 D:\biancheng\vue_vscode\vue-base...
项目初始化完成,可执行以下命令:
cd vue-base
npm install
npm run dev
npm notice
npm notice New major version of npm available! 9.5.1 -> 10.5.2
npm notice Changelog:github.com/npm/cli/rel…
npm notice Run npm install -g npm@10.5.2 to update!
npm notice

安装路由

npm install vue-router@4
  1. 导入路由


目录介绍

目录/文件说明
build项目构建(webpack)相关代码
config配置目录,包括端口号等。我们初学可以使用默认的。
node_modulesnpm 加载的项目依赖模块
src这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件:
assets: 放置一些图片,如logo等。
components: 目录里面放了一个组件文件,可以不用。
App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。main.js: 项目的核心文件。
index.css: 样式文件。
static静态资源目录,如图片、字体等。
public公共资源目录。
test初始测试目录,可删除
.xxxx文件这些是一些配置文件,包括语法配置,git配置等。
index.html首页入口文件,你可以添加一些 meta 信息或统计代码啥的。
package.json项目配置文件。
README.md项目的说明文档,markdown 格式
dist使用 npm run build 命令打包后会生成该目录。

模版语法

  1. 指令 cn.vuejs.org/api/built-i…

浏览器跨域问题

场景代码:
CorsDemo.vue

<template>
    <h1>CorsDemo</h1>
    <div>
        <button @click="getInfo">获取信息</button>
    </div>
    <div>
        info====>>>{{ res }}
    </div>
</template>

<script setup>
import axios from 'axios';
import { ref } from 'vue';
const res = ref();
const getInfo = () => {
    axios.get('http://localhost:2048/api/info').then(
        success => {
            res.value = success.data;
        },
        error => {
            res.value = error.data;
        }
    );
}
</script>

CorsController.java

package wnan.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController("corsController")
public class CorsController {
    @GetMapping("/info")
    public Map<Integer, String> getInfo(){
        Map<Integer, String> map = new HashMap<>();
        map.put(1,"one");
        map.put(2,"two");
        map.put(3,"three");
        return map;
    }
}

运行error:

image.png 解决方法

cors: 这种方式是我工作中处理跨域用到最多也是最简单的一种方式,直接通过注解解决跨域问题,cors解决跨域,一般不用于前端做任何事,而是后端或者服务器去操作,其实就是在服务器里面返回相应的时候加几个响应头,某种程度上来说,cors解决跨域才是真正意义上的解决跨域,但是在开发中,这个响应头不是随便配置的,如果随意配置,就会造成一个问题就算任何人都能找服务器要数据,存在一些安全风险

  1. 后端添加注解【后端】

org.springframework.web.bind.annotation.CrossOrigin; 用于单独的控制器 @CrossOrigin注解是Spring框架中用于处理跨域请求的一个注解。它的主要功能是允许前端应用在发起跨域请求时,后端服务器能够响应并允许这些请求。这样做的目的是为了克服浏览器的同源策略限制,使得跨域请求能够成功进行。

@RestController("corsController")
@CrossOrigin
public class CorsController {}
  1. 全局配置跨域【后端】 单独写一个配置类 CrosConfig.java
package wnan.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        String[] methods = {"GET", "POST", "DELETE", "PUT", "OPTIONS"};
        //addMapping 添加可跨域的请求地址
        // 配置CORS(跨域资源共享)策略,以允许特定的跨域请求
        // 对所有路径进行映射,应用以下CORS规则
        registry.addMapping("/**")
                // 允许所有来源的请求,* 表示任意域名,域名权限 规定由某一个指定的域名+端口能访问跨域项目
                .allowedOrigins("*")
                // 不允许发送凭证(如Cookies),因为这在当前上下文中不是必需的,是否开启cookie跨域
                .allowCredentials(false)
                // 允许指定的HTTP方法通过,methods变量应包含需要允许的方法列表
                .allowedMethods(methods)
                // 指定预检请求(preflight request)的结果可以缓存的最大时间,单位为秒
                .maxAge(3600);
    }
}
  1. 代理【前端】 vit.config.js
export default defineConfig({
  // 定义服务器配置
  server: {
    // 服务器端口
    port: 6930,
    // 代理配置
    proxy: {
      // 定义以'/api'开头的请求代理
      '/api': {
        // 代理目标服务器地址
        target: 'http://localhost:2048',
        // 启用WebSocket代理
        ws: true,
        // 更改代理请求的主机头为目标URL
        changeOrigin: true,
        // 重写代理路径
        pathWrite: {
          // 将请求路径中的'^/api'保留为'/api'
          '^/api': '/api',
        }
      },
    }
  }
})

axios的请求里不要有代理目标服务器地址,比如:http://localhost:2048。 例如:

const getInfo2 = () => {
    axios.get('/api/info').then(
        success => {
            res2.value = success.data;
        },
        error => {
            res2.value = error.data;
        }
    );
}

如果成功:

image.png 如果有http://localhost:2048,则是如下情况,代理失败 image.png image.png

组件间的数据传递

父组件-->子组件

  1. 在父组件中,把变量名写在子组件的标签上
  2. 子组件中使用defineProps()方法里,采用对象的格式,{变量名:变量类型}
  3. props.xxxx的格式调用
  1. 父组件
<template>
<p>这是父组件</p>
<PropsChild greetingMessage="hello" />   
</template>

<script setup>
    import PropsChild from "@/deep-components/PropsChild.vue";
 
</script>
  1. 子组件
    <template>
     <p>这是子组件</p>
      <span>{{ props.greetingMessage }}</span>
    </template>
    <script setup>
    import { defineExpose } from 'vue';

    const props = defineProps({
      greetingMessage: String,
    })

    </script>

image.png

   <template>
    <PropsChild :greetingMessage="data" />
    </template>
    <script setup>
        import { ref } from 'vue'
    
        const data = ref("1");
    </script>

子组件里的props.greetingMessage不具有响应式

子组件-->父组件

  1. 子组件里使用defineEmits(),传入数组,数组格式['子组件事件名称1',.....]
  2. 使用emit('子组件事件名称1',变量值)发送数据到父组件
  3. 父组件里在子组件标签上使用 @子组件事件名称1='父组件事件1'
  4. 父组件事件1=(变量值)=>{ //进行数据传递的操作 }
  5. 2和4的变量值是同一个
  1. 父组件
      <template>
        <p>这是父组件</p>
        <!-- clickChild是子组件绑定的事件,click是父组件接受方式 -->
        <PropsChild @clickChild="clickEven"></PropsChild>
        <span>父组件里显示===>>>{{ child_data }}</span>
      </template>
      
      <script setup>
      import PropsChild from "@/deep-components/PropsChild.vue";
      import { ref } from 'vue'
      
      const child_data = ref('2')
      
      const clickEven = (val) => {
        console.log(val);
        child_data.value = val;
      }
      </script>
  1. 子组件
      <template>
        <p>这是子组件</p>
        <button @click="clickChild">点击子组件</button>
      </template>
      
      <script setup>
      import { defineEmits, ref, defineExpose, reactive } from 'vue';
      
      const emit = defineEmits(['clickChild'])
      const clickChild = () => {
        let content = '子主件的数据';
        console.log('子组件点击了')
        //传递给父组件
        emit('clickChild', content)
      }
      </script>

image.png

image.png

例二

  1. 父组件
      <template>
        <p>这是父组件</p>
        <span>父组件里显示===>>>{{ child_data }}</span>
        <PropsChild @child_data_input="getval"></PropsChild>
      </template>
      
      <script setup>
      import PropsChild from "@/deep-components/PropsChild.vue";
      import { ref } from 'vue'
      
      const child_data = ref();
      const getval=(val)=>{
        child_data.value=val;
      }
      
      </script>
      
      ```
   
   2. 子组件
```vue
      <template>
        <p>这是子组件</p>
        <input v-model="child_data" type="text">
      </template>
      
      <script setup>
      import { defineEmits, ref, defineExpose, reactive,watch } from 'vue';
      
      const child_data = ref("")
      const emit = defineEmits(['child_data_input'])
      
      watch(child_data,(child_data)=>{
        console.log(child_data)
        emit('child_data_input',child_data)
      })
      
      </script>

image.png

image.png

父组件获得子组件的数据ref方法

  1. 需要将组建的属性及方法通过[defineExpose]导出,defineExpose()参数是对象{}
  2. 父组件里在子组件标签里使用ref="自定义变量"
  3. 子定义变量是defineExpose里传递的对象
  1. 父组件
   <template>
     <p>这是父组件</p>
     <span>父组件里显示===>>>{{ child_data_ref }}</span>
   
     <PropsChild ref="child_data_ref"></PropsChild>
     <button @click="dodo">child_data_ref</button>
   </template>
   
   <script setup>
   import PropsChild from "@/deep-components/PropsChild.vue";
   import { ref } from 'vue'
   
   const child_data_ref = ref({});
   
   console.log(child_data_ref.value.info)
   console.log(child_data_ref.value.sex)
   
   function dodo (){
     console.log(child_data_ref.value.info)
     console.log(child_data_ref.value.sex)
   }
   
   </script>
  1. 子组件
   <template>
     <p>这是子组件</p>
   </template>
   <script setup>
   import { defineEmits, ref, defineExpose, reactive,watch } from 'vue';
   
   const info = reactive({
     name: 'huahua',
     age: 18
   })
   const sex = ref('男')
   
   defineExpose({ info, sex })
   </script>

image.png

路由useRouter和useRout的区别

在Vue 3中,useRouter()useRoute() 是Vue Router提供的两个不同的组合式API函数,它们分别用于不同的目的:

  • useRouter()
    useRouter() 函数返回一个路由实例,该实例提供了许多方法,可以让你在组件内进行编程式导航。例如,你可以使用router.push()来导航到不同的URL,或者使用router.replace()来替换当前的历史记录。 以下是一些useRouter()可以使用的路由实例方法:
    • router.push(location, onComplete?, onAbort?): 添加一个新的路由到历史记录栈中。
    • router.replace(location, onComplete?, onAbort?): 在历史记录中替换当前路由。
    • router.go(n): 在历史记录中前进或后退n步。
    • router.back(): 等同于router.go(-1),后退一步。
    • router.forward(): 等同于router.go(1),前进一步。 示例:
import { useRouter } from 'vue-router'
export default {
  setup() {
    const router = useRouter()
    function goToBookDetail(bookId) {
      router.push(`/book/${bookId}`)
    }
    return {
      goToBookDetail
    }
  }
}
  • useRoute()
    useRoute() 函数返回当前路由对象,该对象包含了当前激活路由的详细信息,如params、query、hash等。它是一个只读对象,因此你无法通过它来改变当前路由。 以下是一些可以从useRoute()获取的信息:
    • route.params: 路由参数。
    • route.query: 路由查询参数。
    • route.hash: 当前路由的hash值。
    • route.fullPath: 完整的URL路径。
    • route.matched: 匹配到的路由记录数组。

示例:

import { useRoute } from 'vue-router'
export default {
  setup() {
    const route = useRoute()
    // 获取当前路由的参数
    const bookId = route.params.id
    return {
      bookId
    }
  }
}

总结:

  • useRouter() 用于导航到不同的URL。
  • useRoute() 用于获取当前激活路由的详细信息。

关于依赖安装

scss

npm install -D sass-embedded