当前位置: 首页 > news >正文

Vue2学习记录

前言

这篇笔记,是根据B站尚硅谷的Vue2网课学习整理的,用来学习的

如果有错误,还请大佬指正

Vue核心

Vue简介

Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架

它基于标准 HTML、CSS 和 JavaScript 构建,

并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面


官网:Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org)

初识Vue

  • Vue进行工作,需要提供 Vue实例 和 模版
  • 通过 new Vue() 创建出Vue实例对象
  • 在Vue实例对象中,需要绑定模板
    <!--准备容器--><div id="test01">Hello {{word}}!!</div><script>//创建Vue实例new Vue({el: '#test01',//指定当前实例为那个模版服务data: {word: 'world'}//提供数据,供指定模版使用})</script>

 MVVM模型

Vue 仿照MVVM来进行设计

分为模型(Model),视图(View)和视图模型(ViewModel)三部分

  • M:模型(Model) -> data中的数据
  • V:视图(View) -> 模版,即 DOM
  • VM:视图模型(ViewModel) -> Vue 实例对象

模版绑定 与 data 写法

模版绑定

方法一:

使用 el 来绑定

语法 : el : ' css选择器 '

        new Vue({el: '#test01',data: {word: 'world'}})

方法二:

语法:实例对象 . $mount ( ' css选择器 ' )

        const vm = new Vue({data: {word: 'world!!!'}})vm.$mount('.test01')

data写法

写法一:对象式

语法:data : { 数据对象 }

            data: {word: 'world!!!'}

写法二:函数式

必须返回一个数据对象

不要写箭头函数

            data: function(){return{word:'world!!!'}}

模版语法

Vue 使用一种基于 HTML 的模板语法,

使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上

简单来说:

        将Vue实例中的数据,呈现到 HTML 上

插值语法

可以分析标签体内容(标签包裹内容)

语法:

        {{JS表达式}}

示例:

    <div id="test01">Hello {{word}}<!-- {{}} 中的内容会被替换为Vue实例中的数据--></div><script>new Vue({el:'#test01',data:{word:'world!!!'}})</script>

{{ }} 中的内容会被替换为Vue实例中的数据

指令语法

可以解析标签(标签属性、标签体内容),并可以绑定事件

指令有很多,以 v- 为开头

例:v-bind:  (可简写为 : )

        v-bind : 标签属性 = 'JS表达式'   或   : 标签属性 = 'JS表达式'

    <div id="test02"><a v-bind:href="Prohibited">未满18不要打开</a><!-- "" 中的内容会被替换为Vue实例中的数据--></div><script>new Vue({el: '#test02',data: {Prohibited: 'https://store.steampowered.com/app/2358720/_/'}})</script>

数据绑定

单向数据绑定

语法:

v-bind : 标签属性 = 'JS表达式'   或简写为   : 标签属性 = 'JS表达式'

数据只能从data流向页面

即 修改data中的数据,同时改变页面数据

双向数据绑定

语法:

v-model:value="JS表达式" 或简写为 v-model="JS表达式"

用于有value的标签

数据不仅能从 data 流向页面,还能从页面流向data

即 修改data中的数据,同时改变页面数据 ; 修改页面中的数据,同时改变data数据

数据代理

通过一个对象,代理对另一个对象中的属性的操作(读/写)

Object . defineProperty()

Object . defineProperty()可以为对象添加属性

语法:

Object . defineProperty ( 对象名 , ' 添加属性 ' , {

        get函数 ,

        set函数

})

get函数需要有返回值,作为添加属性的值

当读取所添加属性时,get函数会被调用

当修改所添加属性时,set函数会被调用

        let num = 18let Person = {name: 'zhao',school: 'sn'}Object.defineProperty(Person, 'age', {//读取age时,调用get函数,返回值为age的值get() {return num},//修改age时,调用set函数,修改值作为参数set(value) {num = value//将参数,也就是修改值,传给num}})

使用Object . defineProperty(),实现了Person对num的数据代理,

修改Person的属性值,就可以修改num

Vue中的数据代理

在Vue实例对象中,data的数据存放在Vue._data中

为了更方便地操作data中的数据,Vue通过Object . defineProperty(),

对data中数据进行了数据代理

事件处理 

事件基本使用

使用指令 v-on 来进行事件绑定

语法:v-on : 事件 = " 函数名 "

        简写:@事件 = " 函数名 "

        对应函数需要配置到Vue实例里,methods对象中

    <div><button v-on:click="test01">普通按钮01</button></div><script>const vm=new Vue({el:'div',methods:{test01(){console.log(11111)                    }}})</script>

函数参数

    <div><button v-on:click="test02">普通按钮02</button><button v-on:click="test03(3)">普通按钮03</button><button v-on:click="test04($event,4,44)">普通按钮04</button></div><script>const vm=new Vue({el:'div',methods:{test02(e){console.log(e)console.log(2222)                    },test03(a){console.log(a)console.log(3333)                    },test04(e,a,b){console.log(e,a,b)console.log(4444)}}})</script>

 以上代码为例:

  1. 没有参数时,传入事件对象(test02)
  2. 有参数时,没有事件对象(test03)
  3. 可以用$enevt,来配置事件对象(test04)

注:

  • 不要用箭头函数,因为this将不再指向vm

事件修饰符

用于修饰事件

语法:v-on : 事件 . 事件修饰符 = " 函数名 "

        简写:@事件 . 事件修饰符 = " 函数名 "

事件修饰符作用
prevent阻止事件的默认行为
stop停止事件冒泡
once事件仅触发一次
capture使用事件捕获
selfe.target为当前元素时触发
passive默认行为立即执行,再进行回调函数

示例:

    <div class="out" @click="work">out<div class="in" @click.stop="work"><!--阻止事件冒泡-->in</div></div>

修饰符可以连写

        <div class="in" @click.stop.prevent="work" >

按键修饰符

Vue提供了一些触发键盘事件时使用的按键修饰符

用于在按下某个按键时,触发事件

语法:v-on : 键盘事件 . 按键别名 = " 函数名 "

        简写:@键盘事件 . 按键别名 = " 函数名 "

按键别名为Vue提供,即 按键码的别名

    <!--在按下回车键时触发事件--><input type="text" @keyup.enter="work">

一些常用键盘别名

  • 回车键 ==》enter
  • 删除键 ==》delete
  • 退出键 ==》esc
  • 空格键 ==》space
  • 换行键 ==》tab(最好与keyup使用)
  • 上键 ==》up
  • 下键 ==》down
  • 左键 ==》left
  • 右键 ==》right

未提供的键盘别名可以用按键Key值,使用短横线命名法

系统修饰键

如ctrl,alt,shift,meta(win键)有特殊用法

配合keyup使用:

        按下系统修饰键,再按下并放开其他键时,触发事件

配合keydown使用:

        按下系统修饰键即触发事件

定制按键别名

语法:

        Vue.config.keyCodes.自定义按键名= 键码

计算属性

概念

属性:Vue实例中,data中的都认定为属性

计算属性:所需要的属性不存在,需要通过已有属性来计算获得

计算属性需要配置到Vue实例里,computed对象中

语法:

        const vm=new Vue({el:'.root',data:{属性},computed:{计算属性名:{get函数}}})

通过get()函数来进行计算,需要有return返回值,作为计算属性的值

get(调用时机):

  • 在初次读取计算属性时,get()调用
  • 计算属性所依赖属性数据发生变化时,也会调用

备注:

  • 也可以调用set()函数,进行数据改动
  • get()和set()函数的this均指向Vue实例
  • 计算属性会最终会出现在Vue实例上,直接调用即可

案例:

    <div class="root"><input type="text" v-model:value="xing"><br><input type="text" v-model:value="ming"><br><p>全名:{{quanming}}</p></div><script>const vm = new Vue({el: '.root',data: {xing: '张',ming: '三'},computed: {quanming: {get() {return this.xing + this.ming}}}})</script>

简写

在没有写set()函数时,可以使用简写

语法:

            computed: {计算属性名() {函数体}}
            computed: {quanming() {return this.xing + this.ming}}

监视属性

概念与语法

可以设置被监视的属性,当被监视属性发生改变时,会自行调用函数

写法1:

        const vm = new Vue({el: 'div',watch: {监视属性名: {immediate: 布尔值,//默认为false,是否初始化时调用deep: 布尔值,//默认为false,是否开启深度监视handler(newValue, oldValue) {//newValue为新值,oldValue为旧值函数体}}}})

写法2:

        vm.$watch('监视属性名', {immediate: 布尔值,//默认为false,是否初始化时调用deep: 布尔值,//默认为false,是否开启深度监视handler(newValue, oldValue) {//newValue为新值,oldValue为旧值函数体}})

在监视属性改变时,会调用handler()函数

深度监视 

配置deep: true时开启深度监视

Vue中watch默认不检测对象内部值的改变

开启深度监视可以检测对象内部值的改变

简写

当deep和immediate均没有配置时,可以简写

简写1:

        const vm = new Vue({el: 'div',watch: {监视属性名(newValue, oldValue): {//newValue为新值,oldValue为旧值函数体}}})

简写2:

        vm.$watch('监视属性名', function(newValue, oldValue){//newValue为新值,oldValue为旧值函数体})

计算属性与监听属性区别

  • computed相当于watch更加简单
  • computed能完成的,watch均能完成
  • watch能完成的,computed不一定能完成(watch可进行异步操作)

绑定样式

绑定class

1.字符串写法

直接使用v-bind来绑定样式

可以绑定事件,来动态改变类名

        <div class="main" :class="mood">{{text}}</div>
<head><style>.main {width: 100px;height: 100px;border: 1px solid black;}.test01 {background-color: aqua;}</style><script src="../vue.js"></script>
</head><body><div id="root"><div class="main" :class="mood">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '111',mood: 'test01',}})</script>
</body>

2.数组写法

用于绑定多个样式

可以通过动态操作数组来控制类

<head><style>.work01 {font-size: 20px;}.work02 {color: aqua;}.work03 {font-style: italic;}</style><script src="../vue.js"></script>
</head><body><div id="root"><div class="main" :class="classArr">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '111',classArr: ['work01', 'work02', 'work03']}})</script>
</body>

3.对象写法

用于绑定多个样式,并动态决定用与不用

控制对象中的布尔值,动态决定类的用与不用

<head><style>.work01 {font-size: 20px;}.work02 {color: aqua;}.work03 {font-style: italic;}</style><script src="../vue.js"></script>
</head><body><div id="root"><div class="main" :class="classObj">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '111',classObj: {work01: true,work02: true,work03: true,}}})</script>
</body>

绑定style

1.直接绑定

直接使用v-bind来绑定样式

语法:

        : style = " { 属性(驼峰命名法) : xxx } "

        xxx为Vue示例中的data数据

    <div id="root"><div class="main" :style="{fontSize:fs}">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '1111',fs:'20px'}})</script>

2.对象写法

    <div id="root"><div class="main" :style="styleObj">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '1111',styleObj: {fontSize: '40px',backgroundColor: 'aqua'}}})</script>

3.数组写法

需要在数组中配置对象

    <div id="root"><div class="main" :style="styleArr">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '1111',styleArr: [{fontSize: '40px',backgroundColor: 'aqua'},{color: 'blue'}]}})</script>

条件渲染

v-show

语法:

        v-show = “ 表达式 ”

        表达式值为布尔值

表达式值为false,元素被隐藏,display值为none

v-if

语法:

        v-if = “ 表达式 ”

        后可接v-else-if和v-else

        表达式值为布尔值

表达式值为false时,元素直接被删除,替换为空注释

    <div id="root"><div v-show="false">{{test01}}</div><div v-show="true">{{test01}}</div><br><div v-if="false">{{test02}}</div><div v-if="true">{{test02}}</div></div><script>const vm=new Vue({el:'#root',data:{test01:'111',test02:'222'}})</script>

 列表渲染

v-for遍历

遍历对象

语法:

        v-for = " ( value , key) in 对象名 "  或

        v-for = "  value  in 对象名 "  

        value获取属性值,key获取属性名

    <div id="root"><li v-for="(value,key) in Person">{{value}}----{{key}}</li></div><script>const vm=new Vue({el:'#root',data:{Person:{name:'Tom',age:18,shool:'sdau'}}})</script>

遍历数组 

语法:

        v-for = " ( value , item) in 数组名 "  或

        v-for = "  value  in 对象名 "  

        value获取值,item获取索引

    <div id="root"><li v-for="(value,item) in Arr">{{value}}----{{item}}</li></div><script>const vm = new Vue({el: '#root',data: {Arr: ['A','B','C']}})</script>

key的使用与作用

key的使用

在 v-for遍历 中要添加一个 key属性 

key值的选择,最好使用每条数据的唯一标识

例如ID,身份证,学号等等

如果不添加 key属性 则key值默认为数组或对象的序列号

    <div id="root"><li v-for="(p,item) in Person" :key="p.id">{{p.name}}---{{p.age}}</li></div><script>const vm=new Vue({el:'#root',data:{Person:[{id:'001',name:'wu',age:18},{id:'002',name:'liu',age:20},{id:'003',name:'zhao',age:19},]}})</script>

key的作用和虚拟DOM

虚拟DOM是Vue根据数据生成的

key是虚拟DOM对象的标识,可以理解成虚拟DOM对象的唯一ID

当数据发生改变时,Vue会根据新数据生成新虚拟DOM

新旧DOM会进行对比:

1.若有相同的key值:

  • 若虚拟DOM内容没有变,直接使用真实DOM生成页面
  • 若虚拟DOM内容变化,生成新真实DOM替换之前的

2.若没有相同的key值:

  • 直接建立真实DOM,生成页面 

Vue监视数据原理

基本

Vue会监视data中所有有层次的数据

被监视的对象,会添加get()和set()函数,以实现响应式

( get()和set()函数用自Object . defineProperty())

示例:

            data: {Person: {name: 'Tom',age: 18,shool: 'sdau'},Arr: ['A','B','C']}

注:数组中的数据没有进行监视,但数组本身被监视

如上图,Arr数组有get()和set()函数

如下图,Arr[0]以及其他数据没有get()和set()函数

关于对象

对象中的数据通过 get()和set()函数 监视

对象中后追加的属性,Vue不会进行监视,即不会有get()和set()函数

如果需要监视追加的属性,则需要用到 特定API

语法:

    Vue.set(对象名,属性名,属性值)  另一种写法this.$set(对象名,属性名,属性值)

对象名指被添加属性的对象,注意 ' '

示例:给Person对象添加sex属性,属性值为 男

                addSex() {//Vue.set(this.Person,'sex','男')  另一种写法this.$set(this.Person, 'sex', '男')}

用此API添加的属性,拥有get()和set()函数,会被监视

注:

        该API,不能给vm或vm的根数据对象(data等)添加属性

关于数组

 因为Vue中数组没有get()和set()函数

所有Vue通过其他方式,来实现数组数据的响应式

在数组中修改数据,必须使用以下方法:

  1. 使用API:push(),pop(),shift(),unshift(),splice(),sort(),reverse()
  2. 使用Vue.set() 或 vm.$set().
    Vue.set(数组名,序列,修改值)  另一种写法this.$set(数组名,序列,修改值)

只有使用以上方法数组数据才可以实现响应式

当然,也可以直接修改数组本身,因为数组本身有get()和set()函数

过滤器

定义:
        对要显示的数据进行特定格式化后再显示(用于一些简单的逻辑处理)

注册过滤器(两种方式):

        Vue.filters(过滤器名称,function(){函数体})//全局过滤器或new Vue({filters:{过滤器名称(){函数体}}})//局部过滤器

使用过滤器:

过滤器可以用于插值语法 和 v-bind指令

  • {{ xxx | 过滤器名称 }}
  • v-bind:属性 = " xxx | 过滤器名称 " 

常见内置指令

之前接触过的指令

指令作用简写
v-bind单向绑定解析表达式:xx
v-model双向数据绑定v-model="xx"
v-for遍历数组/对象/字符串
v-on绑定事件监听@
v-if / v-else条件渲染(控制节点是否存在)
v-show条件渲染(控制节点是否展示)

v-text指令

作用:
        向所在节点渲染文本

    <div id="root"><p>{{name}}</p><p v-text="name"></p><p v-text="name">1111</p></div><script>new Vue({el:'#root',data:{name:'zhao'}})</script>

注:
        v-text会替换掉节点中的内容

v-html指令

作用:
        向指定节点中渲染包含html结构的内容

        可以识别html结构

    <div id="root"><div v-html="test"></div></div><script>new Vue({el:'#root',data:{test:'<p>123456</p>'}})</script>

注(v-html有安全性问题):

  1.  在网站上动态渲染任意HTML非常危险,容易导致xss攻击
  2. 在可信内容上使用v-html,不用用在用户提交内容上

v-cloak指令

在网速非常慢的时候,可能会展示未经过Vue渲染的页面

因为网速慢,Vue会加载不出来

可以使用v-cloak指令配合CSS来解决

  • v-cloak没有值
  • v-cloak本质是一个属性
  • v-cloak在Vue加载完成后删除
    <style>[v-cloak]{display: none;}</style><div id="root"><div v-cloak>111</div></div>

v-once指令

  • v-once没有值
  • v-once所在节点只进行初次动态渲染
  • 初次动态渲染完成后,变为静态内容
  • 以后数据变化不会引起所在结构改变

v-pre指令

用于跳过其所在节点的编译过程

        <p v-pre>{{name}}</p>

自定义指令 

函数式

自定义指令可以通过配置到Vue实例里,directives对象中来实现

语法:

        new Vue({directives:{指令名(element,binding){函数体}}})

其中传入的参数:

element为绑定自定义指令标签的DOM对象

binding为DOM对象的相关属性

绑定自定义指令时要加v-

    <div class="root"><p v-test01>1111</p></div><script>const vm=new Vue({el:'.root',directives:{test01(element,binding){console.log(element,binding)}}})</script>

自定义指令中函数调用时机:

  • 指令与元素成功绑定时函数调用
  • 指令所在模板重新解析时函数调用

注:命名如果有多个单词,使用 - 链接

对象式

对象式自定义指令函数调用时机更加细致,会比函数时多一次调用

语法:

        new Vue({directives:{指令名:{bind(element,binding){函数体},inserted(element,binding){函数体},update(element,binding){函数体}}}})

传入的参数同函数式

函数调用时机:

  • bind函数:指令与元素绑定成功时调用
  • inserted函数:指令所在元素被插入页面时调用
  • update函数:指令指令所在模板重新解析时调用

全局自定义指令

通过在Vue实例中配置directives对象所设置的为局部指令

全局自定义指令语法:
        Vue.directive(指令名,配置对象)

        Vue.directive(指令名,回调函数)

    <div class="root"><div v-test03>33</div><div v-test04>44</div></div><script>Vue.directive('test03', {bind(element, binding) {console.log(element, binding)},inserted(element, binding) {console.log(element, binding)},update(element, binding) {console.log(element, binding)}})Vue.directive('test04',function(element, binding){console.log(element, binding)})</script>

生命周期

概念

生命周期 又名:生命周期回调函数,生命周期函数,生命周期钩子

生命周期本质上就是函数

Vue会在特殊时刻帮我们调用的一些特殊名称的函数

生命周期函数名字不可更改,其配置在Vue实例中,其中this指向Vue示例

示例(以mounted为例):

    <script>const vm = new Vue({el: '#root',mounted() {console.log(this)},})</script>

“Vue的一生”

创建(出生)

Vue刚刚创建,仅完成初始化,此时数据监测和数据代理创建还未开始;

初始化完成后,进行数据监测和数据代理创建时,会调用两个生命周期函数(不是Vue创建时)

此时 模板未解析

1.数据监测和数据代理之前,初始化后:

  • 调用beforeCreate函数
  • 此时无法通过vm访问data中的数据,methods中的方法
  • 因为数据监测和数据代理未完成

2.数据监测和数据代理之后,解析模板之前:

  • 调用created函数
  • 此时可以通过vm访问data中的数据,methods中的方法
  • 因为模板未解析,页面不会显示解析内容
挂载(生活)

挂载即把初始的真实DOM元素放到页面

在Vue解析完模板,生成虚拟DOM后,进行虚拟DOM转真实DOM

此时调用两个生命周期函数

1.解析完模板后,挂载完成前:

  • 调用beforeMount函数
  • 页面此时呈现未未经Vue编译的DOM
  • 所有对DOM的操作,最终都不会奏效

2.挂载完成后:

  • 调用mounted函数
  • 对DOM的操作有效,但尽量避免
  • 此时可以进行一些初始化操作,比如开启定时器,发送网络需求等
更新(颠覆三观)

在数据更新时,会调用两个生命周期函数

1.新虚拟DOM生成前:

  • 调用beforeUpdate函数
  • 此时Data数据是新的,但是页面没有进行更新

2.页面更新后:

  • 调用updated函数
  • 此时Data数据和页面都是新的
销毁(逝世)

Vue可以通过Vue.$destroy()来销毁

销毁时会调用两个生命周期函数

1.销毁前(回光返照):

  • 调用beforeDestroy函数
  • 此时Vue的所有配置都还可以使用,即将销毁
  • 一般在此阶段进行关闭定时器,取消订阅的收尾操作

2.销毁后(已寄):

  • 可以调用destroyed函数,但Vue以及没有

注意事项

常用生命周期钩子:

  1. mounted:初始化操作
  2. beforeDestroy:收尾操作

关于销毁Vue:

  • 销毁后自定义事件失效,但原生DOM事件依然有效
  • 一般不会使用beforeDestroy操作Data数据,因为用不到了

Vue组件化编程

组件

实现应用中局部功能代码资源集合

扒一张官网的图(下图):

在一个大盒子中可以分三个中盒子(灰色) ,中盒子又可以分成几个小盒子(深灰色)

这几个盒子中代码和资源的集合可以视为一个组件

作用:组件可以复用编码,简化项目编码

当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用

非单文件组件

特点:一个文件中包含多个组件

Vue使用组件有三步:

  1. 定义组件(创建组件)
  2. 注册组件
  3. 使用组件

定义组件(创建组件)

定义组件需要使用Vue.extend()在全局中进行定义

其中()中传入的内容与 new Vue()需要传入的几乎一模一样

区别:

  • 不写el配置:最终所有组件由vm中的el来决定服务于那个容器
  • data必须写出函数式:避免数据存在引用关系
  • 使用template配置组件结构

示例:

        //定义组件const Person = Vue.extend({template: `<div><p>{{name}}--{{age}}</p></div>`,data() {return {name: 'zhao',age: '18'}}})

注册组件

1.局部注册

在Vue实例中配置components对象

        const vm = new Vue({el: '#Root',//注册局部组件components: {Person: Person//简写:Person}})

2.全局注册

语法:

        Vue.component('组件名', 组件)

        //注册全局组件Vue.component('School', School)

使用组件

在HTML中编写组件标签即可

    <div id="Root"><!--使用组件--><Person></Person><br><School></School></div>

示例代码

<body><div id="Root"><!--使用组件--><Person></Person><br><School></School></div><script>//定义组件const Person = Vue.extend({template: `<div><p>{{name}}--{{age}}</p></div>`,data() {return {name: 'zhao',age: '18'}}})const School = Vue.extend({template: `<div><p>{{name}}--{{address}}</p></div>`,data() {return {name: 'sdau',address: '泰安'}}})//注册全局组件Vue.component('School', School)const vm = new Vue({el: '#Root',//注册局部组件components: {Person: Person//简写:Person}})</script>
</body>

注意事项

组件名
  • 组件名如果由多个单词组成,使用kebab-case命名法:my-school
  • 也可以使用CamelCase命名:MySchool,但是需要Vue脚手架
  • 可以使用name配置指定组件在开发者工具中呈现的名字
        const School = Vue.extend({name:'xxx',template: `<div><p>{{name}}--{{address}}</p></div>`,data() {return {name: 'sdau',address: '泰安'}}})

简写

        const School = Vue.extend(options)

简写为:

        const School = options

组件其他事项

组件的嵌套

组件可以注册在组件中,实现组件的嵌套

示例:

<body><div id="Root"><App></App></div><script>const School = Vue.extend({template: `<div>{{name}}--{{address}}</div>`,data() {return {name: 'sdau',address: '泰安'}}})const Person = Vue.extend({template: `<div>{{name}}--{{age}}</div>`,data() {return {name: 'zhao',age: 18}}})const App = Vue.extend({template: `<div><Person></Person><School></School></div>`,components: {School,Person}})const vm = new Vue({el: '#Root',components: {App}})</script>
</body>

VueComponent

组件的本质是一个名为VueComponent构造函数,由Vue.extend生成

在我们使用组件时,Vue会解析并创建出组件的实例对象

即Vue会帮我们调用 new VueComponent(options)

另外,每次调用Vue.extend,返回值都是一个全新的VueComponent

关于this指向:

  • 组件配置中,this指向均是【VueComponent实例对象】
  • new Vue()配置中,this指向均是【Vue实例对象】

一个内置关系

在Vue中,组件原型对象 的 原型 为Vue示例的 原型对象

即:VueComponent.prototype.__proto__===Vue.prototype

可以让组件实例对象可以访问到Vue原型上的属性和方法

单文件组件

特点:一个文件中只包含1个组件

将非单文件组件中的多个组件进行拆分,写到多个文件中,每个文件就是一个组件

每个组件文件的后缀为 .vue

通过ES6模块化语法进行导出和引入

导出 

组件文件写法:

其中使用 export default { } 来导出组件

<template><div>模板</div>
</template><script>//导出export default {Vue配置项};
</script><style>样式 /*可省略*/
</style>

示例:

<template><div class="test"><h2>{{ name }}--{{ address }}</h2><button @click="show">123456</button></div>
</template><script>
export default {name: "SchoolName",data() {return {name: "sdau",address: "山东泰安",};},methods: {show() {alert("123456");},},
};
</script><style>
.test {background-color: aqua;
}
</style>

引入

引入可以使用 import···from··· 来引入

import 组件名 from "组件地址";

示例:

<template><div><PersonName></PersonName><SchoolName></SchoolName></div>
</template><script>
import PersonName from "./components/PersonName.vue";
import SchoolName from "./components/SchoolName.vue";
export default {name: "App",components: {PersonName,SchoolName,},
};
</script>

ref属性

ref属性用来给元素或子组件注册引用信息(id属性的替代者

语法:

  • 标记(示例):<h1 ref="xxx">···<h1> 或 <组件名 ref="xxx">···</组件名>
  • 获取:this.$refs.xxx

关于获取值:

  • 应用在html标签上,获取真实DOM元素
  • 应用在组件标签上,获取组件示例对象
<template><div id="app"><img ref="img" alt="Vue logo" src="./assets/logo.png" /><HelloWorld ref="hello" msg="Welcome to Your Vue.js App" /><button @click="show">按钮</button></div>
</template><script>
import HelloWorld from "./components/HelloWorld.vue";export default {name: "App",components: {HelloWorld,},methods: {show() {console.log(this.$refs);//返回对象console.log(this.$refs.img);//返回真实DOMconsole.log(this.$refs.hello);//返回组件示例对象},},
};
</script>

配置项props

配置项props可以让组件接受外部传来的数据

当父组件引入其他组件,父组件所需数据子组件没有时,

可以使用配置项props,通过父组件给子组件数据赋值

是一种组件间的通信方式,将数据从父组件传递给子组件

传递与接收

1.传递方(父组件):

    <子组件名 数据名=" 值 "/>

将传入的值传递给子组件

2.接收方(子组件):

  props:['数据名']

接收到父组件传递来的数据

示例:

  • App.vue(传递方,部分代码):
<template><div id="app"><MyPerson name="zhao"/><!--传递--></div>
</template>
  • MyPerson(接收方,部分代码):
<template><div><h1>{{ name }}--{{ age }}</h1></div>
</template><script>
export default {name: "MyPerson",data() {return {age: 18,};},props:['name']//接收
};
</script>

接收的三种方法

接收数据共有三种方法:

1.只接收

  props:['name']

2.限制类型

  props:{name:String//限制name为字符串}

3.限制类型与必要性,指定默认值

  props: {name: {type: String, //限制name为字符串required: true, //必要性default: "zhao", //默认值},},

必要性:父组件必须传值

必要性与默认值一般不在一起使用,有矛盾

mixin(混入)

功能:将多个组件共用的配置,进行提取,成为一个混入对象,进行使用

定义混入

混入可以定义在另一个JS文件中

即多个组件都有的配置,提取到一个JS文件中

export const test={methods:{show(){console.log(this.name);}}
}

通过导出,以便于组件使用

使用混入

局部混入

在引入混入后,可以通过mixins配置项来使用混入

<template><div><h1>{{name}}--{{age}}</h1><button @click="show">123</button></div>
</template><script>
import {test} from './mixin.js'export default {name:'MyPerson',data(){return{name:'zhao',age:18}},mixins:[test]
}
</script>

全局混入

可以直接在App组件中引入混入,使用Vue.mixin(xxx)来进行全局混入

import {test} from './components/mixin'
Vue.mixin(test)

插件

功能:用于增强Vue

本质:插件本质上是一个对象,其中含有一个install方法

install的第一个参数是Vue,所有插件可以实现各种功能

定义插件

对象名.install = function(Vue){函数体
}

使用插件

Vue.use(对象名)

scoped样式

在Vue组件化编程中,每个组件的样式也会影响到其他的组件,产生冲突

作用:

        可以让样式在局部生效,防止冲突

写法:

        <style scoped>

组件自定义事件

组件自定义事件是一种组件间的通信方式,将数据从子组件传递给父组件

绑定

绑定自定义事件都是在父组件中

方法一

直接在父组件中,给子组件绑定事件

    <MyPerson @gainP="getPersonName" />

如上,为子组件MyPerosn绑定名为gainP的事件

触发事件调用getPersonName回调函数

方法二

在生命周期钩子中绑定,用到ref属性

    <MySchool ref="dome" />......mounted() {this.$refs.dome.$on("gainS", this.getSchoolName);},

如上,为子组件MySchool绑定名为gainS的事件

触发事件调用getSchoolName回调函数

整体代码示例(父组件):

<template><div id="app"><p>{{ PersonName }}//{{ SchoolName }}</p><MyPerson @gainP="getPersonName" /><MySchool ref="dome" /></div>
</template><script>
import MyPerson from "./components/MyPerson.vue";
import MySchool from "./components/MySchool.vue";
export default {name: "App",components: {MyPerson,MySchool,},data() {return {PersonName: "",SchoolName: "",};},methods: {getPersonName(test) {this.PersonName = test;},getSchoolName(test) {this.SchoolName = test;},},mounted() {this.$refs.dome.$on("gainS", this.getSchoolName);},
};
</script>

触发

触发自定义事件都是在子组件中

通过触发原生事件来触发自定义事件

语法:

      this.$emit("自定义事件名", 传入数据);

示例: 

  <button @click="givePerosnName">触发事件</button>......methods: {givePerosnName() {this.$emit("gainP", this.Name);},},

如上,触发按钮点击事件,调用givePerosnName函数

在givePerosnName函数中触发gainP自定义事件

并且传入数据this.Name

解绑

解绑事件也是在子组件中

语法:

      this.$off("自定义事件名");

 示例:

  <button @click="relieve">解绑事件</button>......methods: {relieve() {this.$off("gainP");},},

如上,触发按钮点击事件,调用relieve函数

在relieve函数中解绑gainP自定义事件

其他

  • 组件可以绑定原生DOM事件,但是需要 native 修饰符
  • 通过方法二来绑定事件时,回调函数要配置在methods中,或用箭头函数,这样this指向正常,为父组件。使用普通函数,this指向子组件。

全局事件总线

全局事件总线是一种组件之间的通信方式,可以用于任意组件间通信

其并非Vue所提供的方法,而是一种思路,所以写法不唯一

核心思想是找到一个各个组件均可进行通信的中介,来进行任意组件间的通信

虽然写法不唯一,但只记一种

安装全局事件总线

中介可以创建在Vue实例对象的原型上

通过生命周期钩子在Vue实例对象创建完成前安装

在main.js中

new Vue({render: h => h(App),beforeCreate() {Vue.prototype.$bus = this}
}).$mount('#app')

如上:创建名为$bus的中介

使用全局事件总线

接收

接收数据要在接收方组件中,给中介$bus绑定自定义事件

事件的回调配置在接收方组件中

  methods: {getPersonName(test) {this.PersonName = test;},},mounted() {this.$bus.$on('gainP',this.getPersonName)},

如上:

为$bus绑定gainP的自定义事件,函数回调在组件methods配置中

另外,最好在beforeDestroy生命周期钩子中,用$off解绑当前组件所用事件

提供

提供数据只需要在提供方触发$bus的自定义事件即可

      this.$bus.$emit("gainP", this.Name);

消息订阅与发布

消息订阅与发布是一种组件之间的通信方式,可以用于任意组件间通信

1.安装

需要安装pubsub

    npm i pubsub-js

2.引入

import pubsub from 'pubsub-js'

3.接收数据

  methods: {dome(){......}},mounted(){this.pid=pubsub.subscribe('xxx',this.dome)//订阅消息}

4.提供数据

    pubsub.publish('xxx',数据)

5.取消订阅

    PubSub.unsubscribe(pid)

插槽

作用:是一种组件间的通信方式,可以让父组件向子组件指定位置插入HTML结构

           是一种将数据从父组件传递给子组件的方式

默认插槽

父组件(传递方):

设置要传给子组件的HTML结构,需要在使用组件时,在组建标签内写入

    <MyTest><div>Hello World</div></MyTest><!--MyTest为组件名-->

子组件(接收方):

在子组件中需要进行定义插槽,确定传入HTML的插入位置

HTML结构会插入在<slot>标签的位置

<template><div><slot>默认内容</slot><!--如果没有传入HTML,则渲染slot标签内的默认内容--></div>
</template>

 具名插槽

当需要插入多个插槽时,可以用具名插槽

子组件(接收方):

子组件定义多个插槽,并配置name

<template><div><slot name=dome1>默认内容</slot><slot name=dome2>默认内容</slot></div>
</template>

父组件(传递方):

给传递的HTML结构配置solt,值为插槽的name值

    <MyDome><div slot='dome1'>Hello World</div><div slot='dome2'>Hello World</div></MyDome>

作用域插槽

当需要使用的data数据不在传递方父组件自身,而在子组件里时

子组件(接收方):

子组件在定义插槽时,将数据传入插槽中

<template><div><slot :word='word'>默认内容</slot></div>
</template><script>
export default {name: "TheDome",data() {return {word: "Hello World",};},
};
</script>

 父组件(传递方):

必须使用<template>标签,并在标签内配置scope

    <TheDome><template scope="scopeData"> <div>{{ scopeData.word }}</div></template></TheDome>

如上, 子组件传递的数据,以对象形式,给了scopeData

nextTick

语法:

      this.$nextTick(()=>{回调函数})

作用:

        在下一次DOM更新后执行回调

        用于改变数据后,基于更新后的新DOM进行操作时

Vue封装的过渡与动画

如图所示:

Vue封装的过渡与动画分为进入(enter)离开(leave)

进入和离开又分为起点过程中(active)终点(to)

类名

  • 元素进入:
  1. v-enter:进入起点
  2. v-enter-active:进入过程
  3. v-leave-to:进入终点
  • 元素离开:
  1. v-leave:离开起点
  2. v-leave-active:离开过程
  3. v-leave-to:离开终点

在Vue中添加过渡与动画,需要给Vue所配置的类添加样式

过渡/动画

过渡的添加,需要六种样式全部配置

.v-enter,
.v-leave-to {transform: translateX(-100%);
}
.v-enter-to,
.v-leave {transform: translateX(0);
}
.v-enter-active,
.v-leave-active {transition: 1s;
}

使用 <transition>标签将要进行过度的元素进行包裹

    <transition><div class="dome" v-show="xxx">111</div></transition>

被包裹的元素会自行执行样式中所写的过渡

动画的添加,只需要配置v-enter-active和v-leave-active即可,其他同过渡

.v-enter-active {animation: 1s test01;
}
.v-leave-active {animation: 1s test01 reverse;
}
@keyframes test01 {from {transform: translateX(-100%);}to {transform: translateX(0);}
}

多个元素过渡

相同样式:

多个元素,共用一个过渡,需要用 <transition-group>标签包裹

并且每个元素都要指定key值

    <transition-group> <div class="dome" v-show="xxx" key="1">111</div><div class="dome" v-show="xxx" key="2">222</div></transition-group>

不同样式:

多个元素,不共用一个过渡

要为<transition>标签配置name属性

    <transition name='test01'><div class="dome" v-show="xxx">111</div></transition>

在写样式时,类名中的v换成name值

例:

.test01-enter,
.test01-leave-to {transform: translateX(-100%);
}

Vue中的Ajax

Vue脚手架配置代理

配置代理可以解决开发环境 Ajax 跨域问题

在vue.config.js中添加配置

  devServer:{proxy:'xxx'//xxx为服务器基础路径}

优点:

  • 配置简单,请求资源时直接发给前端

缺点:

  • 不能配置多个代理
  • 不能控制请求是否走代理

在vue.config.js中添加配置

devServer:{proxy:{'/dome':{//匹配所有以'/dome'为开头的请求路径target:'xxx',//代理目标的基础路径changeOrigin:true,pathRewrite:{'^/dome':''}}}
}

changeOrigin值为true时,服务器收到请求头中host为服务器基础路径

changeOrigin值为flase时,服务器收到请求头中host为本地基础路径

默认值为true

Vuex

Vuex简介

概念

        专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通信方式,且适用于任意组件间通信。

        简而言之,当多个组件共享数据时,使用Vuex来管理这些共享数据

原理

如图,在Vuex中,封装有actions,mutations,state三个对象,由store统一管理(图未显示)

其中,actions用于响应组件,mutations用于修改数据,state用于存储数据

当组件调用dispatch时,会经过相当于门卫的actions,进行一些逻辑处理

当然也可以绕过actions,调用commit直接到mutations,进行相应数据的修改

在action中调用commit,会到mutations中进行相应数据的修改

搭建Vuex环境

安装Vuex

搭建Vuex环境首先需要在终端中安装Vuex

    npm i vuex

创建store文件

创建路径:src/store/index.js

文件内容:

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)//准备actions对象————响应组件中用户动作
const actions = {}
//准备mutations对象————修改state中的数据
const mutations = {}
//准备state对象————存储数据
const state = {}//创建并暴露store
export default new Vuex.Store({actions,mutations,state
})

传入store配置

在main.js中创建vm时,传入store配置

import Vue from 'vue'
import App from './App.vue'
//引入store
import store from './store' Vue.config.productionTip = falsenew Vue({render: h => h(App),store
}).$mount('#app')

基本使用

组件

在组件中,通过调用dispatch,来触发action

语法:

      this.$store.dispatch('函数名', 数据);

示例: 

  methods: {add() {this.$store.dispatch('add', this.number);//将会触发actions中的add函数,并把this.number传给actions},},

也可以通过调用commit,直接到 mutations中

  methods: {add() {this.$store.commit('add', this.number);//将会触发mutations中的add函数,并把this.number传给mutations},},

actions

在actions中,可以进行一些逻辑处理(如if判断等),然后调用commit

//准备action对象————响应组件中用户动作
const actions = {add(context, value) {context.commit('ADD', value)},
}

在组件中,触发actions的add函数,函数用两个参数

  • context封装有dispatch函数,commit函数,state对象等
  • context中dispatch函数用于调用其他actions中的函数
  • context中commit函数用于触发mutations
  • context中state数据对象,用于进行逻辑处理
  • value则是组件传入的数据

关于commit函数

        context.commit('ADD', value)

将会触发mutations中的ADD函数,并把tvalue传给mutations

mutations

在mutations,进行state的数据处理

//准备mutations对象————修改state中的数据
const mutations = {ADD(state, value) {state.sum += value},
}

其中的ADD函数传入两个参数:state数据对象和actions传入的value

state

state用于存储数据

//准备state对象————存储数据
const state = {sum: 0,
}

回到组件

在组件中,使用 $store.state 即可使用Vuex中的数据

    <div>和为:{{ $store.state.sum }}</div>

getters的使用

概念:

        当state中的数据需要经过加工后再使用时,可以使用getters进行加工

        类似于计算属性,可以当作Vuex中的计算属性

使用:

在index.js中追加getters配置

//准备getters对象————加工数据
const getters = {multiple(state) {return state.sum * 10}
}

并暴露出去

//创建并暴露store
export default new Vuex.Store({actions,mutations,state,getters
})

在组件中,使用 $store.getters 即可使用Vuex中加工后的数据

    <div>10倍和为:{{ $store.getters.multiple }}</div>

map方法

mapState方法

用于映射state中的数据,将其映射为组件中的计算属性

如下传统方法,在组件中,一直使用 $store.state获取数据显得十分麻烦

    <div>和为:{{ $store.state.sum }}</div><div>学校:{{ $store.state.school }}</div><div>姓名:{{ $store.state.name }}</div>

可以直接借助mapState生成计算属性

语法(两种写法)

    //对象写法mapState({ sum: "sum", school: "school", name: "name" }),//或//数组写法mapState(["sum", "school", "name"]),

内容

  mounted(){console.log(mapState({sum:'sum',school:'school',name:'name'}));}

其输出为一个对象,且都是函数,故需要放在计算属性中

使用

import { mapState } from "vuex";
  computed: {//对象写法...mapState({ sum: "sum", school: "school", name: "name" }),},computed: {//数组写法...mapState(["sum", "school", "name"]),},
    <div>和为:{{ sum }}</div><div>学校:{{ school }}</div><div>姓名:{{ name }}</div>

mapGetters方法

用于映射getters中的数据,将其映射为组件中的计算属性

用法与mapState方法无区别

import { mapGetters } from "vuex";
  computed: {//对象写法...mapGetters({ multiple: "multiple" }),},computed: {//数组写法...mapGetters(["multiple"]),},
    <div>10倍和为:{{ multiple }}</div>

mapActions方法

如下传统方法,使用$store.dispatch与actions对话,显得特**烦人

  methods: {add() {this.$store.dispatch("add", this.number);},sub() {this.$store.dispatch("sub", this.number);},addOdd() {this.$store.dispatch("addOdd", this.number);},addWait() {this.$store.dispatch("addWait", this.number);},},

可以靠mapActions方法来解决,省略$store.dispatc,实现组件与actions对话

其语法与mapState无异

内容

  mounted() {console.log(mapActions({ add: "add", sub: "sub" }));},

 其输出也为一个对象,且都是函数,需要放在methods配置中

使用

注意:需要手动在绑定事件时传参!

import { mapActions } from "vuex";
  methods: {//对象写法...mapActions({add: "add",sub: "sub",addOdd: "addOdd",addWait: "addWait",}),},methods: {//数组写法...mapActions(["add", "sub", "addOdd", "addWait"]),},
    <button @click="add(number)">+</button><button @click="sub(number)">-</button><button @click="addOdd(number)">为奇数时加</button><button @click="addWait(number)">一秒钟后加</button>

mapMutations方法

省略$store.commit,实现组件与actions对话

用法与mapActions方法无异

import { mapMutations } from "vuex";
  methods: {//对象写法...mapMutations({add: "add",sub: "sub",addOdd: "addOdd",addWait: "addWait",}),},methods: {//数组写法...mapMutations(["add", "sub", "addOdd", "addWait"]),},

模块化和命名空间

让代码更好维护,让多种数据分类更加明确

修改store

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)const Count01 = {namespaced: true,//开启命名空间actions: {...},mutations: {...},state: {...},getters: {...}
}const Count02 = {namespaced: true,//开启命名空间actions: {...},mutations: {...},state: {...},getters: {...}
}//创建并暴露store
export default new Vuex.Store({modules: {Count01,Count02},
})

不使用map方法

<template><div><!--读取state数据--><p>数:{{ $store.state.Count01.number }}</p><br /><!--读取getters数据--><p>10倍为:{{ $store.getters['Count01/multiple'] }}</p><br /><button @click="add(1)">+1</button><br /><br /><button @click="addIf(1)">为奇数+1</button></div>
</template><script>
export default {name: "TheCount01",methods: {add(value) {//调用committhis.$store.commit("Count01/ADD", value);},addIf(value) {//调用dispatchthis.$store.dispatch("Count01/addIf", value);},},
};
</script>

使用map方法

<script>
import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
export default {name: "TheCount02",computed: {//读取state数据...mapState("Count02", ["number"]),//读取getters数据...mapGetters("Count02", ["multiple"]),},methods: {//调用dispatch...mapActions("Count02", ["addIf"]),//调用commit...mapMutations("Count02", ["ADD"]),},
};
</script>

路由

路由的理解

路由就是一组 key-value 的对应关系

多个路由由路由器进行管理

Vue中通过vue-router插件来实现路由

基本路由

创建router文件

创建路径:src/router/index.js

示例:

//引入VueRouter
import VueRouter from "vue-router";
//引入组件
import TheTest01 from '../pages/TheTest01'
import TheTest02 from '../pages/TheTest02'//创建并暴露router实例对象
export default new VueRouter({routes: [{path: '/test01',component: TheTest01},{path: '/test02',component: TheTest02},]
})

创建的router示例对象中,需要配置一个routers数组,数组存储对象

path值为路由中的key值,component值为组件

组件需要进行引入

安装与应用vue-router插件

搭建vue-router环境首先需要在终端中安装vue-router

npm i vue-router

另外,需要在main.js中应用插件

import Vue from 'vue'
import App from './App.vue'//引入VueRouter
import VueRouter from 'vue-router'
//应用VueRouter
Vue.use(VueRouter)
//引入路由器
import router from './router/index'Vue.config.productionTip = falsenew Vue({render: h => h(App),router: router
}).$mount('#app')

注意在main.js中引入路由器,即router文件

实现组件切换

    <div><div class="a"><router-link active-class="active" to="/test01">test01</router-link></div><div class="a"><router-link active-class="active" to="/test02">test02</router-link></div></div><div><router-view></router-view></div></div>

使用<router-link>标签,实现切换,必需配置to以确定切换的页面

active-class可以配置类名

<router-view>标签,用于指定切换页面的展示位置

<router-view>标签本质是<a>标签

注意点

  1. 路由组件一般存放在pages文件夹中,一般组件存放在components文件夹中
  2. 切换后,未显示的组件默认被销毁,展示时在进行挂载
  3. 每个组件都有独属于自身的$router属性,存储自己的路由信息
  4. 整个应用只有一个routers,可以通过组件的$router属性获取

多级路由

多级路由就是实现路由的嵌套

在router文件中,使用children配置项

    routes: [{path: '/dome01',component: TheDome01},{path: '/dome02',component: TheDome02,//通过children配置子级路由children:[{path:'childdome01',//注意不要写/component:ChildDome01},{path:'childdome02',//注意不要写/component:ChildDome02},]},]

在组件(子组件)中实现跳转要写完整路径

    <div><router-link active-class="active" to="/dome02/childdome01">child01</router-link></div><div><router-link active-class="active" to="/dome02/childdome02">child02</router-link></div>

路由中的query参数

query参数是以路由为媒介,给路由组件传递数据的

传递方

        <router-linkactive-class="active":to="{//注意引号!!path: '/test02',query: {words: 'test02',},}">test02</router-link>

在<router-link>标签中,to配置项写成对象形式,里面写有query对象

query对象中的参数既是传递的数据

另外,也可以使用to的字符串写法,无需配置query,同样可以达到目的

        <router-link active-class="active" to="/test01?words=test01">test01</router-link>
        <router-link active-class="active" :to="`/test01?words=${test01}`">test01</router-link>

接收方(路由组件)

使用$route.query.xxx来接收数据

  <div><p>{{$route.query.words}}</p></div>

虽说是路由中的query参数,但是路由只是一个媒介

传递方组件的数据通过路由传递给路由组件

在此过程中,router文件不需要进行任何修改

命名路由

作用:用于简化路由的跳转

          主要在多级路由中展现其作用

在router文件中,使用name配置项

            children:[{path:'childdome01',//注意不要写/component:ChildDome01,name:'child1'//命名},]

组件中,在<router-link>标签中,to配置项同添加query时一样,需要写成对象形式

      <router-link active-class="active" :to="{name:'child1'}">child01</router-link>

可以配合query配置传递参数

路由中的params参数

params参数和query参数一样,是以路由为媒介,给路由组件传递数据的

路由器修改

在router文件中,要事先使用占位符声明接收参数

            children:[{path:'childdome01/:words',//使用占位符什么接收params参数component:ChildDome01,name:'child1'},]

如上,意为会传递一个名为words的参数

传递方

字符串写法:

直接使用 / 进行拼接

      <router-link active-class="active" :to="`/dome02/childdome02/text2`">child02</router-link>

对象写法:

配置params,并且不可以用path,而是用name

      <router-link active-class="active" :to="{name:'child1',params:{words:'text1'}}">child01</router-link>

接收方(路由组件)

使用$route.params.xxx来接收数据

  <div class="dome"><p>{{$route.params.words}}</p></div>

路由中的props配置

作用:配合query和params参数,让路由组件更方便收到参数

在接收方路由组件中,以$route.params.xxx或$route.query.xxx来接收数据显得特别麻烦

可以在router文件中配置props解决

方法一:

                {path:'childdome01/:words',component:ChildDome01,name:'child1',//值为对象,对象中所有key-value组合通过props传给路由组件props:{name:'test'}},

方法二:

                {path:'childdome01/:words',//使用占位符什么接收params参数component:ChildDome01,name:'child1',//值为布尔值,为true时,把路由收到的所有params参数传给路由组件props:true},

方法三:

                {path:'childdome01/:words',//使用占位符什么接收params参数component:ChildDome01,name:'child1',//为函数,返回值传给路由组件props(route){return{test:route.query.words}}},

replace属性

浏览器的历史记录有两种写入方式:

  • push:追加历史记录
  • replace:覆盖历史记录

追加上的历史记录可以通过点击上图 ← 返回

历史记录被覆盖后就无法返回

路由跳转默认为push,即可以返回

在<router-link>标签中添加replace属性,可以改为replace

      <router-link active-class="active" to="/dome02" replace>dome02</router-link>

编程式路由

作用:无需使用<router-link>标签,即可实现路由的跳转

  methods:{show01(){this.$router.push({path:'/test01'})},show02(){this.$router.replace({path:'/test02'})},}

通过this.$router.push和this.$router.replace两个API来实现

分别以追加历史记录和覆盖历史记录的方式进行跳转路由

其里面的配置同to的对象写法

另外,如果配置name,则name为路由组件的name

其他API:

  • this.$router.forward() 前进
  • this.$router.back()     后退
  • this.$router.go()         传入一个整数,正值则前进,负值后退,跳转数为传入数

缓存路由组件

路由组件在切走后会被销毁

缓存路由组件可以使路由组件在切走后保持挂载,不被销毁

将<router-view>标签包裹在<keep-alive>标签中即可

      <keep-alive include="test01"><router-view></router-view></keep-alive>

<keep-alive>标签中的include属性为保持挂载的路由组件

不配置默认全部保持挂载,有多个时写成对象的形式

路由中特有的生命周期钩子

路由中有两个特有的生命周期钩子

  • activated()        路由组件激活时触发

  • deactivated()    路由组件切走后触发

注意:只有在<keep-alive>标签包裹下有用!

路由守卫

作用:对路由进行权限控制

分类:全局守卫,独享守卫,组件内守卫

全局守卫

全局守卫分为前置守卫和后置守卫

router文件更改

使用全局守卫,需要用到router的API,故不可用以下方式暴露

export default new VueRouter({......
})

 应改为如下代码

const router = new VueRouter({......
})export default router

meta配置

每个路由可以配置meta,这是一个可以让程序员自由传值的配置,meta是一个对象

使用路由守卫需要判断路由是否需要进行权限控制

可以在meta中添加一个布尔值,用于判断

const router = new VueRouter({routes: [{path: '/Person',component: ThePerson,meta: { isAuth: true }},]
})

全局守卫用法

1.全局前置守卫

初始化时执行,以及每次路由切换前执行

router.beforeEach((to, from, next) => {if (to.meta.isAuth) {//判断路由是否需要进行权限控制if (localStorage.getItem('test') === 'xxx') {//判断权限,权限控制的具体规则next()//放行} else {console.log('无权限');}} else {next()//放行}
})

全局前置守卫使用router.beforeEach(),传值为一个函数

函数传三个参数:to, from, next

to, from为对象,分别存储着 切换到的路由组件信息 和 切换走的路由组件信息

next为一个函数,调用时放行,进行路由的切换

2.全局后置守卫

初始化时执行,以及每次路由切换后执行

router.afterEach((to, from)=>{console.log(to, from);
})

一般情况下不用,只需要传递to和from两个参数

因为以及切换完,无需使用next

独享守卫

独享守卫是单独配置在某个路由中的

用于判断某个路由是否需要权限控制

除使用的API外,其他与前置守卫无区别

const router = new VueRouter({routes: [{path: '/Person',component: ThePerson,meta: { isAuth: true },beforeEnter(to, from, next) {if (to.meta.isAuth) {//判断路由是否需要进行权限控制if (localStorage.getItem('test') === 'xxx') {//判断权限,权限控制的具体规则next()//放行} else {console.log('无权限');}} else {next()//放行}}},]
})

组件内守卫

组件内守卫分为进入守卫和离开守卫

进入守卫,在通过路由进入某个路由组件时调用

离开守卫,在通过路由离开某个路由组件时调用

需要写在路由组件中,用法同全局守卫

    //进入守卫beforeRouteEnter(to, from, next){console.log(to, from, next);},//离开守卫beforeRouteLeave (to, from, next) {console.log(to, from, next);}

路由器两种工作模式

对于一个url来说,#后面的内容就是其hash值

hash值不会包含着http请求中,即hash值不会传递给服务器

路由器有两种工作模式:

1.hash模式

  • 地址中永远带着 #
  • 地址可能被第三方App标记为不合法
  • 兼容性高

2.history模式

  • 地址中不带着 #
  • 兼容性比hash模式差
  • 部署后需要后端修404问题

路由默认为hash模式

修改为history模式如下代码:

const router = new VueRouter({mode:'history',.......
})

相关文章:

Vue2学习记录

前言 这篇笔记&#xff0c;是根据B站尚硅谷的Vue2网课学习整理的&#xff0c;用来学习的 如果有错误&#xff0c;还请大佬指正 Vue核心 Vue简介 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。 它基于标准 HTML、CSS 和 JavaScr…...

thinkphp中对请求封装

请求的封装 //调用 $res Http::post($this->baseUrl . $url,$params,[CURLOPT_HTTPHEADER > [Content-Type: application/json,Content-Length: . strlen($params),],]);<?php namespace fast; /*** 字符串类*/ class Http {/*** 发送一个POST请求*/public static …...

网络安全中的数据科学如何重新定义安全实践?

组织每天处理大量数据&#xff0c;这些数据由各个团队和部门管理。这使得全面了解潜在威胁变得非常困难&#xff0c;常常导致疏忽。以前&#xff0c;公司依靠 FUD 方法&#xff08;恐惧、不确定性和怀疑&#xff09;来识别潜在攻击。然而&#xff0c;将数据科学集成到网络安全中…...

通过指令导入/导出vscode扩展插件

导出扩展&#xff1a; 打开VSCode终端&#xff1a; 在VSCode中&#xff0c;你可以通过菜单栏的“终端”选项打开终端&#xff0c;或者使用快捷键Ctrl &#xff08;反引号&#xff0c;通常在键盘左上角&#xff09;。运行导出命令&#xff1a; 在终端中&#xff0c;输入以下命…...

vscode添加环境变量(mujoco)

文章目录 前言一、创建.env文件二、编写setting.jason 前言 之前一直用pycharm&#xff0c;最近改用cursor了&#xff0c;在pycharm中设置环境变量修改运行配置就行了&#xff0c;vscode要麻烦一些&#xff0c;记录一下。 一、创建.env文件 以mujoco环境变量为例&#xff0c;…...

0-1背包问题(1):贪心算法

问题&#xff1a; 有 n 个物品和背包的容量&#xff0c;每个物品的重量为 w[i]&#xff0c;价值为 v[i]&#xff0c;背包的容量为 W。选若干个物品放入购物车&#xff0c;物品不可分割&#xff0c;使价值最大。 问题分析&#xff1a; 首先考虑贪心策略&#xff1a; 每次挑选…...

Qt界面篇:QMessageBox高级用法

1、演示效果 2、用法注意 2.1 设置图标 用于显示实际图标的pixmap取决于当前的GUI样式。也可以通过设置icon pixmap属性为图标设置自定义pixmap。 QMessageBox::Icon icon(...

计算机操作系统——进程控制(Linux)

进程控制 进程创建fork&#xff08;&#xff09;函数fork() 的基本功能fork() 的基本语法fork() 的工作原理fork() 的典型使用示例fork() 的常见问题fork() 和 exec() 结合使用总结 进程终止与$进程终止的本质进程终止的情况正常退出&#xff08;Exit&#xff09;由于信号终止非…...

游戏引擎学习第23天

实时代码编辑功能的回顾 当前实现的实时代码编辑功能已经取得了显著的成功&#xff0c;表现出强大的性能和即时反馈能力。该功能允许开发者在修改代码后几乎立即看到变化在运行中的程序中体现出来&#xff0c;极大提升了开发效率。尽管目前的演示内容较为简单&#xff0c;呈现…...

0基础学java之Day25

Vector /** 知识点&#xff1a;Vector独有的方法 理解&#xff1a; * Vector在JDK1.0开始就已经存在 -- 元老级别的集合类&#xff0c; * 集合框架的概念是JDK1.2开始才有的&#xff0c; * 开发人员为了将Vector保留下来&#xf…...

android集成FFmpeg步骤以及常用命令,踩坑经历

1、入坑第一步:首先集成的库必须正确。最好是有ndk的,FFmpeg有许多个版本,我才开始接触的时候随便选了一个,一般的 方法没有问题。但是涉及到需要使用libx264等条件进行编码时,老是报错,网上搜索资料也没有人说需要ndk的支持才行。这个问题困扰了好几天,怎么试不行,最后…...

Mac——鼠标增强插件Mos

功能说明&#xff1a; 能够解决鼠标断续、不灵敏等鼠标问题。 下载地址&#xff1a; Mac——鼠标增强插件Mos...

【c++篇】:解读Set和Map的封装原理--编程中的数据结构优化秘籍

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 前言一.set和map的初步封装1.树的节点封装修改2.Find()查找函数3.红…...

华为鸿蒙内核成为HarmonyOS NEXT流畅安全新基座

HDC2024华为重磅发布全自研操作系统内核—鸿蒙内核&#xff0c;鸿蒙内核替换Linux内核成为HarmonyOS NEXT稳定流畅新基座。鸿蒙内核具备更弹性、更流畅、更安全三大特征&#xff0c;性能超越Linux内核10.7%。 鸿蒙内核更弹性&#xff1a;元OS架构&#xff0c;性能安全双收益 万…...

ArcGIS API for Javascript学习

一、ArcGIS API for Javascript 介绍 ArcGIS API for Javascript 是由美国 Esri 公司推出&#xff0c;跟随ArcGIS 9.3 同时发布的&#xff0c;是Esri 基于dojo 框架和 REST 风格实现的一套编程接口。通过 ArcGIS API for Javascript可以对ArcGIS for Server 进行访问&#xff…...

LeetCode 3206.交替组 I:遍历

【LetMeFly】3206.交替组 I&#xff1a;遍历 力扣题目链接&#xff1a;https://leetcode.cn/problems/alternating-groups-i/ 给你一个整数数组 colors &#xff0c;它表示一个由红色和蓝色瓷砖组成的环&#xff0c;第 i 块瓷砖的颜色为 colors[i] &#xff1a; colors[i] …...

环形缓冲区

什么是环形缓冲区 环形缓冲区,也称为循环缓冲区或环形队列,是一种特殊的FIFO(先进先出)数据结构。它使用一块固定大小的内存空间来缓存数据,并通过两个指针(读指针和写指针)来管理数据的读写。当任意一个指针到达缓冲区末尾时,会自动回绕到缓冲区开头,形成一个"环"。…...

Maven 仓库

Maven 仓库对于管理构建 Java 项目所需的依赖和插件至关重要。 Maven 仓库主要有三种类型&#xff1a;本地仓库、中央仓库和远程仓库。 本文将探讨每种仓库的用途以及如何有效使用它们。 Maven 仓库类型 本地仓库 本地仓库是位于您本地机器上的一个目录&#xff0c;Maven 在…...

29.UE5蓝图的网络通讯,多人自定义事件,变量同步

3-9 蓝图的网络通讯、多人自定义事件、变量同步_哔哩哔哩_bilibili 目录 1.网络通讯 1.1玩家Pawn之间的同步 1.2事件同步 1.3UI同步 1.4组播 1.5变量同步 1.网络通讯 1.1玩家Pawn之间的同步 创建一个第三人称项目 将网络模式更改为监听服务器&#xff0c;即将房主作为…...

计算机网络习题解答--个人笔记(未完)

本篇文章为关于《计算机网络-自顶向下方法第七版》的阅读总结和课后习题解答(未完待续) 第二章&#xff1a; cookie&#xff1a;&#xff08;这里是比较老版本的HTTP&#xff0c;具体HTTPs是怎么实现的不是很清楚&#xff09;cookie的原理其实很简单。就是在HTTP消息头上又多…...

Unity图形学之雾Fog

1.设置雾化&#xff1a; 2.雾化变化曲线&#xff1a;FogMode &#xff08;1&#xff09;线性&#xff1a; &#xff08;2&#xff09;一次指数&#xff1a; &#xff08;3&#xff09;二次指数&#xff1a; Shader "Custom/FogTest" {Properties{_Color ("Color…...

ML 系列:第 36 节 — 统计学中的抽样类型

ML 系列&#xff1a;第 36 天 — 统计学中的抽样类型 文章目录 一、说明二、抽样方法三、简单随机抽样四、 Stratified Sampling分层抽样五、 Cluster Sampling 整群抽样六、Systematic Sampling系统抽样七、Convenience Sampling便利抽样八、结论 一、说明 统计学中的抽样类型…...

docker-compose部署java服务

文章目录 一、下载安装docker-compose二、编写Dockerfile文件三、编写docker-compose.yml文件配置说明 四、服务启动五、测试与验证 一、下载安装docker-compose 在安装docker时&#xff0c;并不会同时把docker-compose安装好&#xff0c;需要额外安装一下 下载docker-compos…...

ubuntu22开机自动登陆和开机自动运行google浏览器自动打开网页

一、开机自动登陆 1、打开settings->点击Users 重启系统即可自动登陆桌面 二、开机自动运行google浏览器自动打开网页 1、安装google浏览器 sudo wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb sudo dpkg -i ./google-chrome-stable…...

java接口对接标准

概述 最近在跟许多外部平台对接&#xff0c;遇到了很多问题&#xff0c;在此记录一下接口的对接标准。 接口对接标准 确认环境&#xff0c;分别获取di和prd环境的接口信息&#xff0c;比如域名。确认不同环境的防火墙是否连通。接口校验&#xff0c;接口携带的token信息如何…...

训练的decoder模型文本长度不一致,一般设置为多大合适,需要覆盖最长的文本长度么

在训练解码器模型时,文本长度不一致是常见的情况,需要根据任务的特性和数据集的长度分布来设置合理的最大长度 (max_length)。以下是一些指导原则,帮助你设置合适的最大长度: 1. 是否需要覆盖最长文本长度 覆盖最长文本长度: 如果任务对完整性要求很高(例如生成数学公式、…...

安装MySQL服务

安装版本MySQL8的安装包 安装界面 在这里选择MySQL中的Server only 只安装服务器端 如果选择custom需要如下图 进入配置导向&#xff0c;点击ready to configure&#xff0c;点击next即可 采用默认形式 执行成功后&#xff0c;会出现自动选择项 点击next然后再点击Finish 启动…...

十二、正则表达式、元字符、替换修饰符、手势和对话框插件

1. 正则表达式 1.1 基本使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&g…...

Unreal从入门到精通之如何绘制用于VR的3DUI交互的手柄射线

文章目录 前言实现方式MenuLaser实现步骤1.Laser和Cursor2.移植函数3.启动逻辑4.检测射线和UI的碰撞5.激活手柄射线6.更新手柄射线位置7.隐藏手柄射线8.添加手柄的Trigger监听完整节点如下:效果图前言 之前我写过一篇文章《Unreal5从入门到精通之如何在VR中使用3DUI》,其中讲…...

如何提升编程能力第二篇

如何提升编程能力2 1. 引言2. 掌握理论基础2.1 理解编程语言的核心2.2 数据结构与算法2.3 计算机基础与系统设计3.1 多写代码3.2 参与开源项目3.3 开发自己的项目 4. 提高代码质量4.1 代码风格与可读性4.2 测试驱动开发 1. 引言 编程是推动现代科技发展的核心技能&#xff0c;…...

【AI日记】24.11.26 聚焦 kaggle 比赛

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 核心工作 1 内容&#xff1a;研究 kaggle 比赛时间&#xff1a;3 小时 核心工作 2 内容&#xff1a;学习 kaggle 比赛 Titanic - Machine Learning from Disaster时间&#xff1a;4 小时备注&#xff1a;这…...

计算机网络八股整理(一)

计算机网络八股文整理 一&#xff1a;网络模型 1&#xff1a;网络osi模型和tcp/ip模型分别介绍一下 osi模型是国际标准的网络模型&#xff0c;它由七层组成&#xff0c;从上到下分别是&#xff1a;应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff0c;…...

删除链表中的重复元素

删除链表中的重复元素 单链表的创建和使用删除链表中的重复元素 I题目描述解题思路代码实现 删除链表中的重复元素 II题目描述解题思路代码实现 单链表的创建和使用 使用vector结合单链表数据结构创建一个通用单链表。 #include <iostream> #include <vector>str…...

序列求和 牛客网

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 定义S(n) 12 22 … n2&#xff0c;输出S(n) % 1000000007。 注意&#xff1a;1 < n < 1e18。 输入描述: 多组输入&#xff0c;输入直到遇到EOF为止&#xff1b;第一行输…...

【Oracle11g SQL详解】 SELECT 语句的基础用法与示例

SELECT 语句的基础用法与示例 在 Oracle 11g 中&#xff0c;SELECT 语句是最常用的 SQL 语句&#xff0c;用于从数据库表中查询数据。本文将从语法结构、使用方法和常见示例出发&#xff0c;系统讲解 SELECT 语句的基础用法。 一、SELECT 语句的基本语法 SELECT 列名1, 列名2…...

编译以前项目更改在x64下面时报错:函数“PVOID GetCurrentFiber(void)”已有主体

win32下面编译成功&#xff0c;但是x64报错 1>GetWord.c 1>md5.c 这两个文件无法编译 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\winnt.h(24125,1): error C2084: 函数“PVOID GetCurrentFiber(void)”已有主体 1>C:\Program Files (x…...

【小白学机器学习36】关于独立概率,联合概率,交叉概率,交叉概率和,总概率等 概念辨析的例子

目录 1 先说结论 2 联合概率 3 边缘概率 4 (行/列)边缘概率的和 总概率1 5 条件概率 5.1 条件概率的除法公式 5.2 条件概率和联合概率区别 1 先说结论 关于独立概率&#xff0c;联合概率&#xff0c;交叉概率&#xff0c;交叉概率和&#xff0c;总概率 类型含义 …...

如何使用 Tailwind CSS 构建响应式网站:详细指南

文章目录 前言一、安装 Tailwind CSS二、配置 Tailwind CSS三、使用 Tailwind CSS 构建响应式网站四、优化和部署结语 前言 在当今的数字时代&#xff0c;网站不仅需要在桌面浏览器上看起来出色&#xff0c;还需要在移动设备和平板电脑上提供一致的用户体验。响应式设计成为了…...

LabVIEW发动机热磨合试验台

在汽车发动机的研发和质量控制中&#xff0c;发动机热磨合试验是关键环节。它能够检验发动机在实际运行条件下的性能&#xff0c;及时发现异响、振动、漏油等潜在问题。通过搭建基于LabVIEW的高效测试平台&#xff0c;可以显著提高发动机的可靠性和使用寿命。下面介绍LabVIEW开…...

【GPT】力量训练是什么,必要吗,有可以替代的方式吗

什么是力量训练&#xff1f; 力量训练是一种通过抵抗力&#xff08;如重量、阻力带、自身体重等&#xff09;来刺激肌肉收缩&#xff0c;从而提高肌肉力量、耐力和体积的运动形式。它包括以下常见形式&#xff1a; 自由重量训练&#xff1a;使用哑铃、杠铃、壶铃等。固定器械…...

pikachu文件上传漏洞通关详解

声明&#xff1a;文章只是起演示作用&#xff0c;所有涉及的网站和内容&#xff0c;仅供大家学习交流&#xff0c;如有任何违法行为&#xff0c;均和本人无关&#xff0c;切勿触碰法律底线 目录 概念&#xff1a;什么是文件上传漏洞一、客户端check二、MIME type三、getimagesi…...

java hashCode() 详解

hashCode() 是 Java 中 Object 类 提供的一个重要方法&#xff0c;它在 Java 集合框架中扮演着关键角色&#xff0c;特别是在使用哈希表相关的集合&#xff08;如 HashMap、HashSet 和 Hashtable&#xff09;时。以下是对 hashCode() 方法的详解&#xff0c;包括概念、用法、规…...

鸿蒙学习自由流转与分布式运行环境-价值与架构定义(1)

文章目录 价值与架构定义1、价值2、架构定义 随着个人设备数量越来越多&#xff0c;跨多个设备间的交互将成为常态。基于传统 OS 开发跨设备交互的应用程序时&#xff0c;需要解决设备发现、设备认证、设备连接、数据同步等技术难题&#xff0c;不但开发成本高&#xff0c;还存…...

JavaWeb

JavaWeb 一、JavaWeb 是什么&#xff1f;二、JavaWeb 发展阶段三、JavaWeb 常用架构Servlet JSP 架构SSH 架构SSM 架构SpringBoot架构SpringCloud架构 四、JavaWeb 项目结构&#xff08;带web.xml的&#xff09;五、如何打包六、war包部署1. Tomcat 介绍2. Tomcat目录结构3. 开…...

加快发展社会保障事业的必要性

题目 【2011年浙江公务员考试】&#xff08;二&#xff09;某市将召开一次加快发展社会保障事业的形势分析会。会上&#xff0c;某领导要就加快发展社会保障事业的必要性做主题发言。请结合给定资料7~8&#xff0c;为领导拟一份发言要点。&#xff08;25分&#xff09; 要求&a…...

责任链模式在spring security过滤器链中的应用

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许多个对象按照顺序处理请求&#xff0c;并且每个对象可以选择自己是否处理该请求或将其传递给下一个对象。 在Spring Security中&#xff0c;责任链模式得到了广泛应…...

Netty基本原理

目录 前言 原生NIO VS Netty 原生NIO存在的问题 Netty的优点 线程模型 传统阻塞 I/O (Blocking I/O) 2. 非阻塞 I/O (Non-blocking I/O) 3. 多路复用 I/O (Multiplexed I/O) 4. Reactor 模式 常见的 Reactor 模式的变体&#xff1a; Netty线程模型 工作原理 前言 N…...

图论入门编程

卡码网刷题链接&#xff1a;98. 所有可达路径 一、题目简述 二、编程demo 方法①邻接矩阵 from collections import defaultdict #简历邻接矩阵 def build_graph(): n, m map(int,input().split()) graph [[0 for _ in range(n1)] for _ in range(n1)]for _ in range(m): …...

Haproxy

一、haproxy简介 HAProxy 是法国开发者 威利塔罗 (Willy Tarreau) 在 2000 年使用 C 语言开发的一个开源软件 是一款具备高并发 ( 万级以上 ) 、高性能的 TCP 和 HTTP 负载均衡器 支持基于 cookie 的持久性&#xff0c;自动故障切换&#xff0c;支持正则表达式及 web 状态统…...

旋转磁体产生的场 - 实验视频资源下载

先发几个视频&#xff0c;是2019年所作的实验内容 更多视频&#xff0c;到某宝找我吧。注意&#xff1a;是收费的。 20190312-180244-旋转磁体产生的场造成激光功率减小 https://download.csdn.net/download/u014161757/90038058 20190313-090956-旋转磁体产生的场对真空介电…...