vue3的知识整理

news2024/12/28 23:33:51

1. vue3的生命周期

vue3的生命周期一般有2种形式写法,一种是基于vue2options API的写法,一种是vue3特有的Composition API

options API的生命周期
基本同vue2的生命周期基础,只是为了与生命周期beforeCreatecreated对应,将beforeDestroydestroyed更名为beforeUnmountunmounted,使用方法同vue2

<template>
  <p>生命周期</p>
  <p>{{msg}}</p>
  <button @click="changeMsg">修改值</button>
  <button @click="toHome">跳转页面</button>
</template>
<script>
import { useRouter } from 'vue-router'

export default {
  name: 'lifeCycles',
  data() {
    return  {
      msg: 'hello vue3'
    }
  },
  setup() {
    console.log('setup')

    // 在`setup`函数中创建`router`对象,相当于vue2中的`this.router`
    const router = useRouter()
    const toHome = () => {
      router.push({
        path: '/'
      })
    }
    return {toHome}
  },
  beforeCreate() {
    console.log('beforeCreate');
  },
  created() {
    console.log('created');
  },
  beforeMount() {
    console.log('beforeMount');
  },
  mounted() {
    console.log('mounted');
  },
  beforeUpdate() {
    console.log('beforeUpdate');
  },
  updated() {
    console.log('updated');
  },
  // 由vue2 beforeDestroy改名
  beforeUnmount() {
    console.log('beforeUnmount');
  },
  // 由vue2 destroyed改名
  unmounted() {
    console.log('unmounted');
  },
  methods: {
    changeMsg() {
      this.msg = 'after changed'
    }
  }
}
</script>
初次渲染时

点击修改值的生命周期

点击跳转,组件销毁的生命周期

composition API的生命周期
composition API的生命周期钩子函数是写在setup函数中的,它所有生命周期是在vue2生命周期名字前加on,且必须先导入才可使用

在这种写法中,是没有onBeforeCreateonCreated周期的,setup等同于(或者说是介于)这两个生命周期

<template>
  <p>composition API生命周期</p>
  <p>{{msg}}</p>
  <button @click="changeMsg">修改值</button>
  <button @click="toHome">跳转页面</button>
</template>
<script>
import { useRouter } from 'vue-router'
// 必须先导入生命周期
import { 
  onBeforeMount, 
  onMounted, 
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted
} from 'vue'
export default {
  name: 'lifeCycles',
  data() {
    return  {
      msg: 'hello vue3'
    }
  },
  setup() {
    console.log('setup')
    onBeforeMount(() => {
      console.log('onBeforeMount');
    })
    onMounted(() => {
      console.log('onMounted');
    })
    onBeforeUpdate(() => {
      console.log('onBeforeUpdate');
    })
    onUpdated(() => {
      console.log('onUpdated');
    })
    onBeforeUnmount(() => {
      console.log('onBeforeUnmount');
    })
    onUnmounted(() => {
      console.log('onUnmounted');
    })

    // 在`setup`函数中创建`router`对象,相当于vue2中的`this.router`
    const router = useRouter()
    const toHome = () => {
      router.push({
        path: '/'
      })
    }
    return {toHome}
  },
  
  methods: {
    changeMsg() {
      this.msg = 'after changed'
    }
  }
}

</script>
初次渲染

点击修改data中的值

页面跳转,组件销毁

2. 如何理解 Composition API 和 options API ?

Composition API带来了什么:

  • 更好的代码组织
  • 更好的逻辑复用,避免mixins混入时带来的命名冲突和维护困难问题
  • 更好的类型推导

options API
使用options API,当代码很多时,即当data, watch, methods等有很多内容时,业务逻辑比较复杂,我们需要修改一部分时,可能要分别到data/methods/模板中对应修改,可能需要我们在页面反复横跳来修改,逻辑块会比较散乱。

Composition API
Composition API则会将业务相关的部分整合到一起,作为一个模块,当要修改,统一到一处修改,代码看起来会更有条理

image.png

它包含的内容包括:

  • reactive
  • ref相关(ref, toRef, toRefs,后面会具体介绍)
  • readonly
  • watch和watchEffect
  • setup
  • 生命周期钩子函数

两者的选择:

  • 不建议共用,否则容易引起混乱(思路、组织方式、写法都不太一样)
  • 小型项目,业务逻辑简单的,建议用options API,对新手也比较友好
  • 中大型项目、逻辑复杂,建议使用Composition API

Composition API它属于高阶技巧,不是基础必会的,有一定的学习成本,是为了解决复杂业务逻辑而设计,就像hooksReact中的地位一样

3. 如何理解ref,toRef,toRefs

ref

  • 通过ref方式创建响应式的值类型,并赋予初始值,并通过.value的方式获取值或修改值
  • 通过reactive方式创建响应式的引用类型,并赋予初始值,修改和获取方式同普通对象一样
  • 除了以上两种用法,还可以使用ref来声明dom元素,也就是类似vue2中的用法
<template>
  <p>ref demo</p>
  <p>{{nameRef}}今年{{ageRef}}岁了</p>
  <p>他喜欢{{hobbies.type}}</p>
</template>

<script>
// 导入ref, reactive, onMounted
<template>
  <p>ref demo</p>
  <p>{{nameRef}}今年{{ageRef}}岁了</p>
  <p>他喜欢{{hobbies.type}}</p>
  <p ref="eleRef">我是refTemplate使用方式的内容</p>
</template>

<script>
import { ref, reactive, onMounted } from 'vue'
export default {
  name: 'ref',
  setup() {
    // ref
    const ageRef = ref(3); // ref创建响应式的值类型,并赋予初始值
    const nameRef = ref('小花')
    console.log(ageRef.value) // 通过.value方式获取值
    ageRef.value = 18 // 通过.value方式修改值

    // reactive
    const hobbies = reactive({
      type: 'basketball'
    })
    console.log(hobbies.type) // basketball,通过obj[key]方式获取值
    hobbies.type = 'aaaaa' // 通过obj[key]=xxx方式修改值

    // refTemplate
    const eleRef = ref(null)
    onMounted(() => {
      // 跟vue2的区别在于,vue2使用this.$refs['eleRef']方式获取dom,这里通过eleRef.value方式获取
      console.log(eleRef.value) // dom
      console.log(eleRef.value.innerHTML) // 我是refTemplate使用方式的内容

    })
    
    // 注意,这些对象都要return出去,否则就不是响应式
    return {
      ageRef,
      nameRef,
      hobbies,
      eleRef
    }
  }
}
</script>

image.png

PS: 小建议, ref定义的数据可以加个 Ref后缀,这样就能区分 refreactive定义的变量了

toRef

看定义有点绕

  • 针对一个响应式对象(reactive封装)的属性prop
  • 通过toRef创建一个ref对象,这个ref对象和reactive对象的某属性两者保持引用关系

注意,如果toRef是通过普通对象来生成ref对象,那么普通对象和ref对象都将不是响应式的

<template>
  <p>toRef demo</p>
  <p>小花今年 - {{ageRef}}岁 - {{state.age}}岁</p>
</template>

<script>
import { toRef, reactive } from 'vue'
export default {
  name: 'toRef',
  setup() {
    // 定义一个响应式的reactive引用对象
    const state = reactive({
      name: '小花', 
      age: 3
    })

    // 如果是普通对象,使用toRef,那么它们将都不是响应式的
    // 也就是说ageRef和state都不是响应式
    // const state = {
    //   name: '小花', 
    //   age: 3
    // }

    // 通过toRef创建一个响应值类型ageRef, 这个ageRef和state.age属性保持双向引用
    const ageRef = toRef(state, 'age')

    // 修改state.age值时,ageRef也会跟着改
    setTimeout(() => {
      state.age = 25
    }, 1000)

    // 修改ageRef值时,state.age也会跟着改
    setTimeout(() => {
      ageRef.value = 30
    }, 2000)

    return {
      state, ageRef
    }
  }
}
</script>
初始时

1s后,state.age改了,ageRef也跟着改了

2s后,ageRef改了,state.age也跟着改了

toRefs

  • 将响应式对象(reactive)的所有属性prop,转换为对应prop名字的ref对象
  • 两者保持引用关系
<template>
  <p>toRef demo</p>
  <!-- 这样,模板中就不用写state.name, state.age了,直接写name和age即可 -->
  <p>{{name}}今年 - {{age}}岁</p>
</template>

<script>
import { toRefs, reactive } from 'vue'
export default {
  name: 'toRef',
  setup() {
    // 定义一个响应式的reactive引用对象
    const state = reactive({
      name: '小花', 
      age: 3
    })

    // 相当于
    // const age = toRef(state, 'age')
    // const name = toRef(state, 'name')
    // const stateAsRefs = { age, name }
    const stateAsRefs = toRefs(state)

    // 修改state.age值时,就会映射到ref类型的age上
    setTimeout(() => {
      state.age = 25
    }, 1000)

    // return stateAsRefs 等同于:
    // const { age: age, name: name } = stateAsRefs
    // return { age, name }
    return stateAsRefs
  }
}
</script>

应用:
当使用composition API时,抽象出一个模块,使用toRefs返回响应式对象,这样,在接收的时候,我们就可以使用解构的方式获取到对象里面的内容,这也是比较符合我们常用的方式

// 封装一个模块,使用toRefs导出对象
export function useFeature() {
  const state = reactive({
    x: 1,
    y: 2
  })
  // ...
  return toRefs(state)
}
// 导入时,可以使用解构方式
import { useFeature } from './features'
  
export default {
  setup() {
    // 可以在不丢失响应式的情况下解构
    const  { x, y } = useFeature()
    return { x, y }
  }
}

ref, toRef, toRefs 使用小结:

  • reactive做对象的响应式,用ref做值类型的响应式
  • setup中返回toRefs(state),或toRef(state, prop)
  • ref变量命名建议用xxxRef
  • 合成函数返回响应式对象时,使用toRefs
为什么需要 ref ?
  • 如果没有ref,普通的值类型定义,没法做响应式
  • computed,setup,合成函数,都有可能返回值类型,要保证其返回是响应式的
  • 如果vue不定义ref,用户可能会自己造ref,反而更加混乱
为什么需要.value ?
  • ref是一个对象(保证响应式),value用来存储值
  • 通过.value属性的getset实现响应式
  • 用于模板、reactive时,不需要.value,这是因为vue编译会自动识别,其他情况则需要使用
为什么需要 toRef 和 toRefs ?
  • 目的:为了不丢失响应式的情况下,把对象数据分散、扩散(或者说是解构)
  • 前提:针对的是响应式对象(reactive封装的对象)
  • 本质:不创建响应式(创建是ref和reactive的事),而是延续响应式

4. watch和watchEffect的区别

  1. watchwatchEffect都可以监听data的变化
  2. watch需要指定监听的属性,默认初始时不会触发,如果初始要触发,需要配置immediate: true
  3. watchEffect是不需要指定监听的属性,而是自动监听其用到的属性,它初始化时,一定会执行一次,这是为了收集要监听的属性
<template>
  <p>watch 的使用</p>
  <p>numberRef: {{numberRef}}</p>
  <p>{{name}}-{{age}}</p>
</template>

<script>
import { ref, reactive, toRefs, watch, watchEffect } from 'vue'
export default {
  name:'Watch',
  setup() {
    const numberRef = ref(1000)
    const state = reactive({
      name: '小花', 
      age: 3
    })
    // 监听ref变量
    watch(numberRef, (newVal, oldVal) => {
      console.log('watch:', newVal, oldVal);  
      // watch: 1000 undefined
      // watch: 200 1000
    }, {
      immediate: true // 第三个参数可选,是一些配置项,immediate表示初始化时就执行监听
    })

    setTimeout(() => {
      numberRef.value = 200
    }, 1000)

    // 监听对象
    watch(
      // 第一参数是监听对象,如果是对象需要使用函数返回形式
      () => state.age,
      // 第二个参数是监听的变化值
      (newVal, oldVal) => {
        console.log('watch:', newVal, oldVal);  
        // watch: 3 undefined
        // watch: 18 3
      },
      // 第三个参数是配置项
      {
        immediate: true, // 初始变化就监听
        deep: true // 深度监听
      }
    )
    setTimeout(() => {
      state.age = 18
    }, 1000)

    return {
      numberRef,
      ...toRefs(state)
    }
  }
}
</script>
watch
  // watchEffect监听
    watchEffect(() => {
      console.log('watchEffect');
      console.log(numberRef.value);
      console.log(state.age);
    })
watchEffect

5. 在setup中怎么获取组件实例

  • setup和其它compostion API中没有this
  • 如果一定要获取,要使用getCurrentInstance获取,并且在挂载后才可获取数据
  • 如果是options API,则可以像vue2一样正常使用this
<template>
  <p>get instance</p>
</template>

<script>
import { getCurrentInstance, onMounted } from 'vue'
export default {
  name: 'GetInstance',
  data() {
    return  {
      x: 1,
      y: 2
    }
  },
  // composition API
  // 没有this,需要getCurrentInstance来获取组件实例
  // 且setup本身是beforeCreate和Created生命周期间的钩子,拿不到data,所以要在onMounted中获取
  setup() {
    console.log('this', this);  // this undefined

    const instance = getCurrentInstance()
    console.log('instance', instance.data.x); //  instance undefined

    onMounted(() => {
      console.log('instance', instance.data.x); // instance 1
    }) 
  },
  // options API
  mounted() {
    console.log(this.x);  // 1
  }
}
</script>

6. vue3升级了哪些重要的功能

参考官网升迁指南

createApp
// vue2
const app = new Vue({/*options*/})
Vue.use(/*...*/)
Vue.mixin(/*...*/)
Vue.component(/*...*/)
Vue.directive(/*...*/)

// vue3
const app = Vue.createApp({/*options*/})
app.use(/*...*/)
app.mixin(/*...*/)
app.component(/*...*/)
app.directive(/*...*/)
emits属性
  1. setup中可以使用emit向父组件发出事件
  2. 在子组件中,需要emits声明向父组件发出的事件集合
<template>
  parent
  <Child msg="hello" @log="log" />
</template>
<script>
import Child from './child.vue'
export default {
  name: 'emits',
  components:{
    Child
  },
  methods: {
    log() {
      console.log('child emit me!')
    }
  }
}
</script>
<!-- Child.vue -->
<script>
export default {
  name: 'child',
  props: {
    msg: {
      type: String
    }
  },
  emits: ['log'],  // 需要声明接收的父组件传递的方法
  // 在setup方法中,可以使用emit方法与父组件通信
  setup(props, {emit}) {
    emit('log')
  },
  methods: {
    one(e) {
      console.log('one');
    },
    two(e) {
      console.log('two');
    }
  }
}
</script>
多事件处理
<template>
  <!-- 可以同时触发多个事件 -->
  <button @click="one($event), two($event)">触发多事件</button>
</template>
fragment

vue2只允许template中只有一个元素,如果多个元素,必须用一个元素包裹
vue3则允许template中可以直接有多个元素,这样就可以减少dom层级

移除.sync

vue2中的.sync

vue2中使用.sync是对以下语句的语法糖,父组件通过v-bind:xxx.sync='xxx'来向子组件说明这个属性是双向绑定的,子组件中通过$emit('update:xxx', newVal)来更新这个值

<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

<!-- sync语法糖 -->
<text-document v-bind:title.sync="doc.title"></text-document>

vue3中,废除了.sync的写法,换成一种更具有语义的写法v-model:xxx,在父组件中使用v-model:xxx方式说明这个属性是双向绑定的,子组件中通过$emit('update:xxx', newVal)来更新这个值

<template>
  <p>{{name}}-{{age}}</p>

  <UserInfo 
    v-model:name="name"
    v-model:age="age"
  />
</template>

<script>
import { reactive, toRefs } from 'vue'
import UserInfo from './userInfo.vue'
export default {
  name: 'vmodel',
  components: {
    UserInfo
  },
  setup() {
    const userInfo = reactive({
      name: '小花',
      age: 3
    })
    return toRefs(userInfo)
  }
}
</script>

<!-- userInfo.vue -->
<template>
  <input type="text" :value="name" @input="$emit('update:name', $event.target.value)">
  <input type="text" :value="age" @input="$emit('update:age', $event.target.value)">
</template> 
<script>
export default {
  props: {
    name: {
      type: String
    },
    age: {
      type: String
    }
  }
}
</script>
异步组件的导入方式不一样

vue2child: () => import('child.vue')
vue3:需要defineAsyncComponent导入,child: defineAsyncComponent(() => import('child.vue'))

teleport

teleport将我们的模板移动到DOMVue app之外的其他位置,比如可以使用teleport标签将组件在body

<template>
  <p>这是放在当前组件下的内容</p>
  <teleport to="body">
    <p>假设这是个弹窗,直接放到body下</p> 
  </teleport>
</template>
image.png
最后编辑于:2024-09-27 20:39:29


喜欢的朋友记得点赞、收藏、关注哦!!!

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

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

相关文章

餐企中场战事:高端网红退败,平价品牌向前

餐饮行业&#xff0c;风起云涌。人人都在讨论逆流与寒气的今天&#xff0c;品牌何以为战&#xff1f;步入平价时代&#xff0c;又该如何寻找制胜法宝&#xff1f; 01风浪越大&#xff0c;餐饮机会越多 如果把餐饮业的历史无限拉长&#xff0c;你会发现每个看似经济下行的节点…

Chromium 中前端HTMLDialogElement <Dialog> c++代码实现

一、HTMLDialogElement: open property Baseline Widely available The open property of the HTMLDialogElement interface is a boolean value reflecting the open HTML attribute, indicating whether the <dialog> is available for interaction. Value A boole…

CENTOS上的网络安全工具(三十)DPDK和HyperScan环境构建

一、预备知识 由于DPDK涉及到强CPU相关的优化策略&#xff0c;以及对网卡驱动栈的替换&#xff0c;所以在开始之前&#xff0c;首先需要垫补点CPU相关的概念&#xff0c;以及Linux上和网卡驱动相关的管理命令。 &#xff08;一&#xff09;CPU架构及相关概念 1. Socket、Core…

社交网络中的AI趋势:Facebook的创新探索

在数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术的迅速发展正在深刻改变社交网络的面貌。作为全球最大的社交媒体平台之一&#xff0c;Facebook在AI领域的创新探索&#xff0c;不仅提升了用户体验&#xff0c;还推动了整个社交网络生态的演变。本文将深入探讨…

Linux操作系统分析实验-用户与内核共享内存,实验二

Linux操作系统分析实验-多线程与内核模块编程&#xff0c;实验一_实验一 多线程与内核模块编程-CSDN博客 一、实验目的 1、理解Linux进程地址空间、虚拟内存、物理内存的概念&#xff1b; 2、理解物理内存分配和回收原理。 3、利用链表实现动态内存分配。 4、了解共享内存…

VMtools安装办法解决本地与虚机拷贝

一、打开虚拟机选项-重新安装VMware Tools 二、等待虚拟机开启&#xff0c;点开运行(WinR)输入D:/setup.exe 前提正常引用虚拟机光盘介质&#xff0c;保证光驱位置处于D盘&#xff0c;下一步进行安装完成。

Golang | Leetcode Golang题解之第466题统计重复个数

题目&#xff1a; 题解&#xff1a; func getMaxRepetitions(s1 string, n1 int, s2 string, n2 int) int {n : len(s2)cnt : make([]int, n)for i : 0; i < n; i {// 如果重新给一个s1 并且s2是从第i位开始匹配 那么s2可以走多少位&#xff08;走完了就从头开始走p1, p2 :…

Jenkins pipeline语法笔记

Jenkins pipeline 简介Jenkins Pipeline 优势DSL 是什么 pipeline支持两种语法&#xff1a;声明式pipeline语法&#xff1a;Pipelineagent Pipeline 声明式语法DeclarativeenvironmentoptionsparameterstriggerstoolsinputwhenParallel Pipeline Scripted语法流程控制Declarati…

【HarmonyOS】HMRouter使用详解(三)生命周期

生命周期&#xff08;Lifecycle&#xff09; 使用HMRouter的页面跳转时&#xff0c;想实现和Navigation一样的生命周期时&#xff0c;需要通过新建生命周期类来实现对页面对某一个生命周期的监控。 新建Lifecycle类 通过继承IHMLifecycle接口实现生命周期接口的方法重写。 通过…

20240904 华为笔试 二叉树消消乐

文章目录 题目解题思路代码BUG 代码最终代码题目 题目描述 给定原始二叉树和参照二叉树(输入的二叉树均为满二叉树,二叉树节点的值范围为[1,1000],二叉树的深度不超过1000),现对原始二叉树和参照二又树中相同层级目值相同的节点进行消除,消除规则为原始二叉树和参照二又树中…

进程概念三

1&#xff0c;运行状态R 1&#xff0c;理论&#xff1a; 在cpu中&#xff0c;有一个结构体&#xff1a;runqueue组成的一个双向链表&#xff0c;里面记录着对应的进程的代码和数据&#xff0c;存在内存中随时准备被调度&#xff0c;这种时候就叫做运行状态 2&#xff0c;why&a…

25西安电子科技大学考研预报名人数信息—公布

01报名信息直播 西安电子科技大学之前考研收集信息表现在公布&#xff0c;本次收集涉及到833、834、893&#xff08;原953&#xff09;专业&#xff0c;即计算机科学与技术学院、人工智能学院、网络与信息安全学院、卓越工程师学院 对于大家想提问的问题&#xff0c;学长学姐将…

AI智能聊天问答系统源码+AI绘画系统+图文搭建部署教程,文生图图生图,TTS语音识别输入,AI智能体,文档分析

一、前言 人工智能的快速进步吸引了全球的瞩目&#xff0c;各式AI应用如绘图、语言模型和视频处理等已在多个领域获得应用。这些技术不仅加速了科技的创新&#xff0c;也在艺术创作、内容生产和商业实践等方面显示了其巨大潜力。例如&#xff0c;AI语言模型极大提升了内容自动…

Cursor 与 DeepSeek API 的完美融合

在当今的编程领域中&#xff0c;选择合适的工具对于提高编程效率和质量至关重要。今天&#xff0c;我们将深入探讨如何将强大的 AI 辅助编程工具 Cursor 与优秀的 DeepSeek API 进行配置&#xff0c;以实现更加高效的编程体验。 一、Cursor&#xff1a;强大的 AI 辅助编程工具…

前端实现-搜索关键字标红处理

1、实现效果 2、代码实现 searchNotes(data, value) {const searchTerms = value.split( );const aData = [];for (let i = 0; i < data.length; i++) {const item = data[i];let titleMatches = true;let gaishuMatches = true;for (const term of searchTerms) {if (!ite…

Docker 的使用-01

一、Docker 设置和镜像源 1.1、设置 #查看 Docker 信息 docker version docker info#守护线程启动&#xff1a; systemctl daemon-reload 重启Docker服务&#xff1a; systemctl restart docker#关闭Docker服务 sudo systemctl stop docker#启动Docker服务 systemctl start d…

finereport制作带刷新和滚动的明细表

1、数据库查询 SELECT * FROM S订单 limit 602、配置页面内容 里面配置 订单明细 right(now(), 8) FORMAT(today(), "EEEE", "Locale.UK") today()3、时间按秒刷新 # 全页面刷新&#xff0c;则可用以下js: setInterval(“self.location.reload();”,1000…

AI 仅有大模型吗?AI Agent 究竟有多牛?

今天来和大家聊一个当下科技领域特别火爆的概念——AI Agent&#xff01; 前世界首富在其个人博客上写道&#xff1a; AI Agent&#xff08;AI智能体/助理/助手&#xff09;“将彻底改变计算机使用方式&#xff0c;并颠覆软件行业”。 他还预言“Android、iOS和Windows都是平…

喜讯!迈威通信TSN产品通过“时间敏感网络(TSN)产业链名录计划”评测,各项指标名列前茅

TSN技术&#xff0c;作为推动企业网络化与智能化转型的关键力量&#xff0c;已成为工业网络迈向下一代演进的共识方向&#xff0c;正加速重构工业网络的技术架构与产业生态。为响应这一趋势&#xff0c;工业互联网产业联盟携手中国信息通信研究院及50余家产学研用单位&#xff…

leetcode---素数,最小质因子,最大公约数

1 判断一个数是不是质数(素数) 方法1&#xff1a;依次判断能否被n整除即可&#xff0c;能够整除则不是质数&#xff0c;否则是质数 方法2&#xff1a;假如n是合数&#xff0c;必然存在非1的两个约数p1和p2&#xff0c;其中p1<sqrt(n)&#xff0c;p2>sqrt(n)。 方法3&…