首页 > 其他分享 >Vue笔记

Vue笔记

时间:2023-06-06 09:12:45浏览次数:43  
标签:... Vue 笔记 state 组件 data store

Vue笔记

vuex-router-sync插件:

https://segmentfault.com/a/1190000037680351

学到vue.js路由就没学了!

还有过渡和动画、混入、AJAX、响应接口没学

进度:https://learning.dcloud.io/#/?vid=5

https://cn.vuejs.org/v2/guide/index.html模板组件化应用构建

//问题:props是什么?

技巧:

  • 在vue中编写的界面,.vue文件浏览器是不认识的,通过vue-template-compiler包进行编译,这个包在使用vue-cli创建项目的时候就自动安装了
  • 0、null、undefined、false 时为false,其他值为true
  • 三目运算符:A?B:C 若A为true则返回B,否则返回C。 A,B,C都是表达式(数字)
  • 我们经常在created()中请求服务器数据,并存放到data中
  • 我们经常在updated()中获取最新的已经更新的数据和DOM结构
  • debugger以代码的方式,作为断点来用,独占1行
<div v-bind:class="[errorClass ,isActive ? activeClass : '']"></div>很常用!

$refs和$emit作用相反

@blur失去焦点时触发

@focus获得焦点时触发

@click单击时触发(点击)

@tap更加好的单击时触发(移动端的滑动、触摸,按住)

若实例属性名中间有'-',则整个变量要加引号!如'text-danger',不然无法显示。可以中间使用'_'。如'text_danger'。

Vue特性

  1. 数据驱动视图
  2. 双向数据绑定

MVVM

image-20220426082903652

image-20220426083014944

npm安装库

在dependencies中的库【开发+部署+上线】从头到尾都需要用到。

在devDependencies中的库,仅在开发阶段用到!

npm install 库名【@版本】 --save
install 可以换成 i  
--save可以换成-S
--save或-S的作用是将库名写入到package.json的dependencies中,可以省略
npm install 库名【@版本】 -D
-D是  --save-devd
-D的作用是将库名写入到package.json的devDependencies中

template的作用

image-20220112172418790

随便加!就是个包裹作用!,不影响程序运行,不会渲染到页面上

除了#id是属于el的,其他出现的变量都是data的,其他出现的方法都是methods的

  • Vue 构造器中有一个el 参数,它是 DOM 元素中的 id

  • data 用于定义属性,实例中有三个属性分别为:site、url、alexa。

  • methods 用于定义的函数,可以通过 return 来返回函数值。

  • {{ }} 用于输出对象属性和函数返回值。

  • 引用Vue 实例属性,都要加前缀 $,以便与用户定义的属性区分开来。

  • 如:
    var data = { site: "菜鸟教程", url: "www.runoob.com", alexa: 10000}
    var vm = new Vue({
        el: '#vue_det',
        data: data
    })
    引用1:vm.$el   //实例定义的
    引用2:vm.$data //实例定义的
    引用3:vm.data  //用户定义的
    //使用$可以对原本定义的实例的属性进行补充
    

watch监听器-之后可以通过vm.$watch进行补充

<script>
var app = new Vue({
    el: '#app',
    data:{
        info:{username:"admin"},
        size:null,
        kilometers:null,
        meters:null,
        
    }
    watch: {
        
        //方法格式的监听器定义
        size: function(){ //size是监听的变量名,每次改变就调用后面的函数,这里没有参数,视情况而定
        	this.objectStyle.fontSize = this.size + 'px'
       	}
       	//也可以
       	size:function(value){
       		this.objectStyle.fontsize = value + 'px'
       	}
       	
       	kilometers:function(val) {   //每次改变值作为变量val传入函数
            this.kilometers = val;
            this.meters = this.kilometers * 1000
        },
        meters : function (val) {   //每次改变值作为变量val传入函数
            this.kilometers = val/ 1000;
            this.meters = val;
        },
    	
    //对象格式的监听器定义
    	meters : {
            //当数据改变之后,会自动调用handler函数
            handler (newVal,oldVal) {   
            	this.kilometers = val/ 1000;
            	this.meters = val;
       		 },
  //immediate当浏览器打开的时候就立即调用一次handler,默认值是false      
             immediate:true,
  //若监听是一个对象,想要监听对象里面每一个属性的变化的话使用deep
 //只要监听对象的任何一个属性发生了改变,就触发handler函数,默认值是false
            deep:true,
        }
    //监听对象的单一属性:
    'info.username':{
        handler(newVal){
            console.log(newVa)
        }
    }
    	
   	}
</script>

vm.$watch必须定义在实例化之后,是对定义的修改(添加方法),如果有需要获取之前的值和之后的值的话,需要两个参数(第一个为最新的数据,第二个为老的数据)。如果就一个参数则默认是最新的数据作为参数

 <script>
  //每次调用(变量发生改变),new->old,newer->new
 // $watch 是一个实例方法//kilometers是监听的变量名,后面的匿名函数固定第一个为改变后,第二个为改变前的变量
vm.$watch('kilometers', function (newValue, oldValue) {
// 这个回调将在 vm.kilometers 改变后调用
	document.getElementById ("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
		})
 </script>
//等价于
<script>
    var app = Vue({
        el = '#ass',
        watch:{
        
        	kilometers:function(newValue,oldValue){
        		document.getElementById ("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
        
    		}
    	}
    })
</script>

数组常用方法

forEach

image-20220428200602485

some

image-20220428200533655

every-返回布尔值【判断所有的情况】

image-20220428200744909

filter-过滤出所有为true的数据集合

image-20220428201428493

reduce-累加

image-20220428201715313

缩写

v-bind 缩写

Vue.js 为两个最为常用的指令提供了特别的缩写:

<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- 缩写 :-->
<a :href="url"></a>   //和CSS的伪类差不多

v-on 缩写

<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- 缩写 @-->
<a @click="doSomething"></a>

v-slot缩写

<!-- 完整语法 -->
<template v-slot:header>xxxxxx<template>
<!-- 缩写 #-->
<template #header>xxxxxx<template>

Vue-设置鼠标悬停提示-v-bind

image-20220102212414121

v-bind绑定的值不能是保留字!如class、id、href...

v-bind本身的作用指的是动态修改HTML属性而已,DOM元素本身可以写HTML属性,也可以都有v-bind规定

所有HTML的属性前都要加v-bind,右边可以使用data中定义的变量,如下:

  • v-bind:class="{'class1':use}"

    //use是一个布尔值,true则class=class1,false则没有,常和v-model联动改变use,从而改变DOM元素的class然后就能动态的更改DOM元素的样式

  • 一般v-bind:class="class2"

  • v-bind:title="message" // message在data中

  • v-bind:id="'list_id' + id" // id在data中

  • v-bind:href="url" // url在data中

  • v-bind:target="target" //target在data中

v-bind

class={键:值},一般值是放data,以便动态修改

//第一种:设置单个动态变量
v-bind:class="{'class1':use}" 

//use是一个布尔值,tvuerue则class=class1,false则没有,常和v-model联动改变use,从而改变DOM元素的class然后就能动态的更改DOM元素的样式


//第二种:设置多个动态变量
//若isActive和hasError同时为true,则两个CSS样式合并,相同的部分后面覆盖前面
//若其中一个为true,另一个为false,则只执行true的样式和class名
//div本身也可以写class,反正v-bind可以动态修改
<div class="static"
     v-bind:class="{ 'active' : isActive, 'text-danger' :hasError }">
</div>

//第三种:使用数组设置多个动态变量
<div id="app">
	<div v-bind:class="[activeClass, errorClass]"></div>
</div>
<script>
new Vue({
  el: '#app',
  data: {
    activeClass: 'active',   //class=active对应一个CSS样式
    errorClass: 'text-danger'//class='text-danger'对应一个CSS样式
  }
})
</script>

//第四种:通过computed计算属性对象返回class的值
<style>
.base {
  width: 100px;
  height: 100px;
}

.active {
  background: green;
}

.text-danger {
  background: red;
}
</style>
<div id="app">
  <div v-bind:class="classObject"></div>
</div>
<script>

new Vue({
  el: '#app',
  data: {
    isActive: true,
    error: {
      value: true,
      type: 'fatal'
    }
  },
  computed: {
    classObject: function () {  //同时返回3个值,若全true,先合并,后面的覆盖前面的相同的CSS
      return {
        base: true,//true
        active: this.isActive && !this.error.value,   //false
        'text-danger': this.error.value && this.error.type === 'fatal', //true
      }
    }
  }
})
</script>



style={键:值;键:值;} 所有样式可以封装成字典对象

//样式封装成对象直接绑定
<div id="app">
  <div v-bind:style="styleObject">菜鸟教程</div>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    styleObject: {
      color: 'green',
      fontSize: '30px'
    }
  }
})
</script>

//可以使用数组使用多个样式对象,合并样式,相同则向前覆盖
<div id="app">
  <div v-bind:style="[baseStyles, overridingStyles]">菜鸟教程</div>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    baseStyles: {
      color: 'green',
      fontSize: '30px'
    },
	overridingStyles: {
      'font-weight': 'bold'
    }
  }
})

Vue-if语句-v-if,若不满足则不显示,满足则显示

ps:v-if换成v-show也能达到同样的效果。如果频繁切换显示不显示,则使用v-show更好,否则v-if更好

pps:v-show会在加载html的时候-加载完整代码

<p v-if="seen">现在你看到我了</p>

<script type="text/javascript">
var app3 = new Vue({
	el: '#app-3',
	data: {
		seen: true
	}
})
</script>

image-20220102212537799

v-else-if-和v-if一起用

 <div v-if="type === 'A'">
      A
    </div>
    <div v-else-if="type === 'B'">
      B
    </div>
    <div v-else-if="type === 'C'">
      C
    </div>
    <div v-else>
      Not A/B/C
</div>

v-else-和v-if一起用

div id="app">
    <div v-if="Math.random() > 0.5">
      Sorry
    </div>
    <div v-else>
      Not sorry
    </div>
</div>
    
<script>
new Vue({
  el: '#app'
})
</script>

Vue-调用函数-methods


<div id="app-5">
  <p>{{ message }}</p>
  <button v-on:click="reverseMessage">反转消息</button>//事件定义直接用方法名
    //这里加"()"也行,已解决。如果事件绑定的方法没有参数可以选择加括号也可以不加括号
</div>
methods: {
    reverseMessage: function () {
      this.message = this.message.split('').reverse().join('')
    }
  }

字符串方法:charAt(index)

a = "asdasfgrg"
a.charAt(0)//a
a.charAt(3)//a
a.charAt(2).toUpperCase()//D

字符串方法:slice(index)

截取字符串:从index往后截取

Vue-for循环-v-for

官方建议,用到v-for,必须要绑定一个key,最好是id【唯一标识】,而且只能是字符串或者数字类型

<li v-for="todo in todos" :key="todo.id">  //todos是一个数组,每个元素是一个字典
      {{ todo.text }}      //打印每个字典的键为text的值
</li>
<script typy="text/javascript">
    var app4 = new Vue({
		el: '#app-4',
		data: {
			todos: [{
                	id:"1",
					text: '学习 JavaScript'
				},
				{
                    id:"2",
					text: '学习 Vue'
				},
				{
                    id:"3",
					text: '整个牛项目'
				}
			]
		}
	})
</script>

v-model

image-20220111171451797

Vue 提供了 v-model 指令,它能轻松实现表单输入和应用状态之间的双向绑定。

即:input中的message和p中的message是同一个,VUE中修改message,则两个同时改!!!

常用于:

input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定

v-model等价于

<input v-model="parentData">//直接双向绑定
//等价于
<input 
    :value="parentData" //data改变input值改变
    @input="parentData = $event.target.value"//input值改变data改变
>
v-model双向绑定对比
text和textarea元素使用value属性和input事件
:value='xxx'
@input='aaa'

checkbox和radio使用checked属性和change事件
:checked='xxx'
@change='aaa'

select使用value和change事件
:value='xxx'
@change='aaa'
<div id="app-6">
  <p>{{ message }}</p>
  <input v-model="message">//input的value->data的message->DOM中的所有message
    //input默认值为message,input的value值和message绑定。同时若修改input的值,则整个app的所有message都会修改
</div>

<script>
new Vue({
  el: '#app',
  data: {
    message: 'Runoob!'
  }
})
</script>

//通过v-model可以将数据作为参数传入Vue实例定义的函数
<div id="A">
<input type="txet" placeholder="请输入字符!" v-model="inp"></input>
<h2 v-if="calLen(inp)>10">输入的字符长度大于10</h2>
<h2 v-else-if="calLen(inp)>5">输入的字符长度大于5</h2>
</div>
<script>
new Vue({
  el: '#A',
  data: {
    inp:'' 
  },
  methods{
    calLen:function(value){
    	if (!value){
            return 0;
        }else{
            return value.split(' ').length;
        }
        
    }
}
})
</script>

//绑定的变量的类型和值决定了初始选中的状态
//若绑定的变量是布尔型,则复选框的value也只能是布尔型
//若重载复选框的value,则value为固定值,但此时绑定的变量不可用是布尔类型和"",只能是数组"[]"
<div id="app">
  <p>单个复选框:</p>
  <input type="checkbox" id="checkbox" v-model="checked">
  <label for="checkbox">{{ checked }}</label>
	
  <p>多个复选框:</p>
  <input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames">
  <label for="runoob">Runoob</label>
  <input type="checkbox" id="google" value="Google" v-model="checkedNames">
  <label for="google">Google</label>
  <input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames">
  <label for="taobao">taobao</label>
  <br>
  <span>选择的值为: {{ checkedNames }}</span>
</div>

<script>
new Vue({
  el: '#app',
  data: {
	checked : false,
    checkedNames: []
  }
})
</script>

//单选按钮,可以绑定变量是使用任何类型作为初值("",[],t),也可以直接使用单选按钮的value
<input type="radio" id="runoob" value="Runoob" v-model="picked">
...
picked : 'Runoob'
...

//下拉框:选中的option的value和selected绑定(select要和optiony)
<select v-model="selected" name="fruit">
    <option value="">选择一个网站</option>
    <option value="www.runoob.com">Runoob</option>
    <option value="www.google.com">Google</option>
</select>
...
data: {
	selected: '' 
  }
...

表单修饰符

.lazy (v-model默认是同步数据的,加上这个修饰符不会马上同步数据,而会在change事件中同步,也就是失去焦点或按下回车键才更新数据)

也就是会在@change="doThis" 事件触发的时候才会更新数据
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >

.number (v-model会将输入的数据转变成数字类型)

<input v-model.number="age" type="number">

.trim (v-model会将输入的数据自动去掉两边的空格)

<input v-model.trim="msg">

Vue-内嵌HTML代码-v-html

<div id="app-7">
	<p v-html="HTML"></p>//可以是标签块也可以是文字
</div>
<script type="text/javascript">
    var app7 = new Vue({
		el: '#app-7',
		data: {
			HTML:'<span style="color: red">this is </span>'
		}
	})
</script>

Vue-内容覆盖-v-text

<div id="app">
    <p v-text="username">AAA</p>
</div>
<script type="text/javascript">
    var app7 = new Vue({
		el: '#app',
		data: {
			username:"asdasd"
		}
	})
</script>

结果p输出asdasd,覆盖原来的AAA

Vue-{

image-20220426110348123

Vue-监听器-v-on

//如果事件绑定的方法没有参数可以选择加括号也可以不加括号
<div id="app-5">
  <p>{{ message }}</p>
  <button v-on:click="reverseMessage">反转消息</button>
  <button v-on:click="reverseMessage2">反转消息</button>//computed:必须无参,不能和methods重名
  <button v-on:click="reverseMessage()">反转消息</button>//都行,以后还是都加吧!
</div>

事件修饰符

image-20220426155556649

修饰符是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()

<form v-on:submit.prevent="onSubmit"></form>     //""(双引号)中是是定义在实例中的方法
<a v-on:click.stop="doThis">
//缩写
<form @submit.prevent="onSubmit">
<a @click.stop="doThis">
  • .stop - 阻止冒泡(若有很多嵌套,默认从内向外冒泡,若无.stop,执行最外层的触发事件;若有则.stop加在哪就在哪一层停住,执行该层的触发事件)

  • .prevent - 阻止默认事件

  • .capture - 捕获事件(若很多层嵌套,每一层都加.capture,则会从外向内捕获,捕获最里面的触发事件)

  • .self - 只监听触发该元素的事件。

  • .once - 只触发一次

  • .native - 监听父组件的事件。若不加只能通过子组件$emit触发,若加了可以主动触发

  • .sync-当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。 .sync 它会被扩展为一个自动更新父组件属性的 v-on 监听器。也就是说(子组件接收到的prop的值做了改变,父组件的相应的也会改变,最后由于父组件改变,子组件传入的值再改变)

    以下是鼠标事件:

  • .left - 左键事件

  • .right - 右键事件

  • .middle - 中间滚轮事件

    <!-- 阻止单击事件继续传播 -->
    <a v-on:click.stop="doThis"></a>
    
    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>
    
    <!-- 修饰符可以串联 -->
    <a v-on:click.stop.prevent="doThat"></a>
    
    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>
    
    <!-- 添加事件监听器时使用事件捕获模式 -->
    <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
    <div v-on:click.capture="doThis">...</div>
    
    <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
    <!-- 即事件不是从内部元素触发的 -->vue
    <div v-on:click.self="doThat">...</div>
    
    注意:使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。

    因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

按键修饰符-在当前界面按下指定的键时触发

<input v-on:keyup.13="submit">//按下ASCII码为13的键
<input v-on:keyup.13.16="submit">//按下ASCII码为13和16的键
<input v-on:keyup.enter="submit">
//缩写
<input @keyup.enter="submit">
<input @keyup.alt.67="submit">//按下Alt+C   :C的ASCII是67啊!

常用的按键别名:

  • .enter
  • .tab
  • .delete (捕获 "删除" 和 "退格" 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift
  • .meta

动态组件-Vue内置-is属性

动态组件方式每次发生组件切换,旧的组件就会被销毁,新的组件就会被创建

image-20220428222210662

使用keep-alive保持状态

保持组件在被销毁的时候,不被销毁

image-20220428224111149

image-20220428223937369

deactivated和activated生命周期函数

image-20220428224224804

keep-alive的include和exclude属性

默认是将keep-alive的所有子标签做缓存表示,但可以设置include属性和exclude属性,只能二选一,看实际情况。多个组件之间用逗号分割

image-20220429094152249

Vue-组件-模板-自己DIY-简化代码

注册全局组件和局部组件

image-20220427153803703

定义名为 todo-item 的新组件
全局注册组件在main.js【入口文件】中
<script type="text/javascript">//全局组件
Vue.component('todo-item', {         //注册名为todo-item的组件,可以在html中直接用,使用<todo-item></todo-item>
  template: '<li>这是个待办项</li>'    //使用todo-item等价于使用li
  methods: {   //还可以定义方法
  }
})
//组件的妙处不止如此:还可以更多
var app = new Vue(...)
</script>


局部注册组件,只能在app-7这个Vue实例中用
<script type="text/javascript">//局部组件,定义在一个Vue实例中
    var Child = {
  		template: '<h1>自定义组件!</h1>'
	}
    var app7 = new Vue({
		el: '#app-7',
		data: {
			HTML:'<span style="color: red">this is </span>'
		},
        components:{
        	test:{  //局部组件名
        		template: '<li>这是个待办项</li>' ,
        		methods: {   //还可以定义方法
    			}
 			}
            test2:Child//可以使用先前定义好的模板对象
    	}
    })
</script>

组件也可以加data-必须定义为函数和实例化不同

//定义成函数放回值的好处就是创建的组件每个data都是独立的,会渲染到模板中去
//组件data必须是一个函数
<script>
    Vue.component('button-counter2', {
    
    data: function () {
	    // data 选项是一个函数,组件不相互影响
        return {
            count: 0,
            aaa: 3,
            bbb:'sd'
      		...
        }
    },
   
    template: '<button v-on:click="count++">点击了 {{ count }} 次。</button>'
})
</script>

组件属性-props-可以是任何类型(StringNumberObjectBoolenArray等)

<div id="app">
	<todo-item aaa="world!" message="hello!"></todo-item>
</div>
<script>
    //以全局注册的组件为例:todo-item是template的父组件
    //todo-item可以通过设置message,传入子组件。然后子组件代替父组件展示
    Vue.component('todo-item', {   
        props:['message','aaa'],
  		template: '<li>{{message}},{{aaa}}</li>'    
})
    //结果显示:hello!world!
</script>

但是怎么区分props传入的类型呢?-那就要使用prop验证

子组件在接受数据的时候,可以指定接收具体类型的数据、是否不能为空,是否有默认值等。

当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告

type 可以是下面原生构造器:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

type 也可以是一个自定义构造器,使用 instanceof 检测。

<script>
    //若不需要验证则直接props:[propA,propB,propC,propD,propE,propF]
    //若需要见下面:
Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,  //可以是String`、`Number`、`Object`、`Boolen`、`Array`,若就单纯检查类型
    
    propB: [String, Number],// 多个可能的类型,使用数组。          全都不匹配就会报错!
    
    propC: {
      type: String,    //若有多个属性,则判断类型和其他分离,使用type!
      required: true  // 必填的字符串,必须传值,不传报错!
    },
   
    propD: {
      type: Number,
      default: 100  // 带有默认值的数字,可选,若没传值就使用默认值!
    },
    
    propE: {
      type: Object,  // 对象或数组默认值必须从一个工厂函数获取
      default: function () {   // 带有默认值的匿名函数对象
        return { message: 'hello' } //字符串对象,对象名为message
    //返回数组对象的三个方法
    //第一种
    default:function(){
         return{aaa:[]}//返回一个空数组对象,对象名为aaa
     }
    //第二种    
     default:function(){
         return{[]}//返回一个空数组对象
      }
     //第三种    
     default:()=>[]//返回一个空数组对象
       
    },
    
    propF: {//这个value就是父组件传入的值
      validator: function (value) {// 自定义验证函数
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})
</script>

动态props-很简单-使用v-bind

父组件改变,子组件改变;但是子组件改变,父组件不会改变

props是单向绑定

<div id="app">
	<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>//v-for每次获取一个字典对象,传入子组件,然后子组件代替父组件
</div>
<script>

    Vue.component('todo-item', {   
        props:['todo'],
  		template: '<li>{{todo.text}}</li>'    
	})
    
    var appa=Vue({
        el="#app",
        data:{
        	sites: [
                { text: 'Runoob' },
                { text: 'Google' },
                { text: 'Taobao' }]					
    	}
    })
    //结果显示:因为<li>是有序列表,所以有数字
    //1.Runoob
    //2.Google
    //3.Taobao
</script>

Vue $emit 若父组件事件,可以使用这个来触发

语法:this.$emit(“父组件事件名”,"父组件触发函数的传递值1(可选)",“传递值2”,...)

若父组件有参数则,按顺序传入,若无则无需传递参数

传递多个参数时,父组件的触发函数必须要有arguments这个参数,子组件将多个参数作为数组传入arguments,后面有例子

image-20220428094050442

<div id="app">
    <div id="counter-event-example">
      <p>{{ total }}</p>
      <button-counter v-on:increment="incrementTotal"></button-counter><br/>
      <button-counter v-on:increment="incrementTotal"></button-counter>
    </div>
</div>
<script>
    Vue.component('button-counter', {
  template: `<div>
  <button v-on:click="incrementHandler(1)">-</button>{{ counter }}<button v-on:click="incrementHandler(2)">+</button>
    		</div>`,//template写在引号内,使用``可以实现template多行
  data: function () {  //data在父组件中必须是个函数,每个实例可以维护一份被返回对象的独立的拷贝
    return {
      counter: 0
    }
  },
  methods: {
    incrementHandler: function (v) {
        if(v==1){
            this.counter -= 1
              this.$emit('increment',1)//给父组件的incrementTotal传入1
        }else{ 
            this.counter += 1
              this.$emit('increment',2)//给父组件的incrementTotal传入2
        }
      
    }
  },
})
new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal: function (d) {
        if(d==1){
            this.total -= 1
        }else{
            this.total += 1
        }
      
    }
  }
})
</script>

//传递多个参数            父组件必须要有arguments这个参数!要一模一样
<div id="app">
    <div id="counter-event-example">
      <p>{{ total }}</p>
      <button-counter v-on:increment="incrementTotal(arguments)"></button-counter><br/>
      <button-counter v-on:increment="incrementTotal(arguments)"></button-counter>
    </div>
</div>
<script>
Vue.component('button-counter', {
  template: '<div><button v-on:click="incrementHandler(1)">-</button>{{ counter }}<button v-on:click="incrementHandler(2)">+</button></div>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    incrementHandler: function (v) {
        if(v==1){
            this.counter -= 1
              this.$emit('increment',1,2)//父组件arguments=[1,2]
        }else{ 
            this.counter += 1
              this.$emit('increment',2,1)//父组件arguments=[2,1]
        }
      
    }
  },
})
var app=new Vue({    //var app=可以省略使用匿名实例,若只需要1个实例的话
  el: '#counter-event-example',
  data: {
    total: 0,
    a:0,
    b:0
  },
  methods: {
      //这边必须要用this,表明是app实例中的
    incrementTotal: function (d) {   //d就是arguments是一个参数数组
      	this.a=d[0];
      	this.b=d[1];
      if (this.a==1 && this.b==2){
        this.total-=1;
      }else if(this.a==2 && this.b==1){
        this.total+=1;
      }

      
    }
  }
})
</script>

兄弟【只要不是父子皆兄弟】组件实现传值-eventbus

image-20220428095856485

image-20220428095916356

自定义组件实现v-model双向绑定的功能:

(自定义组件不能使用v-model,因为自定的组件并没有默认的value和input事件,但使用model选项可以解决,详见后面):

正向:

1、实例的price决定父组件的value的值因为v-bind

2、子组件input通过props内的属性得到父组件的value的值

反向:

1、子组件input通过输入触发了input事件,会将自身的value值传入对应的函数

2、函数负责触发父组件的input事件并且给它对应的函数传参,此时这个参数就是子组件的value值

3、父组件的input被触发会执行一个函数并且有一个由子组件传来的value值

4、父组件的函数执行将子组件的value赋给实例的price

至此结束,完成双向绑定!!!

直接v-model的实质就是price=组件的value,组件的value=price

// HTML部分
<div id="app">
    // 4.父组件的value值绑定到price
    <price-input :value="price" @input="onInput"></price-input>
</div>
// js部分
<script>
    Vue.component('custom-input',{
        // 1.监听input,输入时触发自定义组件内部的updateVal事件
        template: `<input :value='value' @input='updateVal($event.target.value)' type='text'></input>`,
        // 5.通过props传递,实现父组件值绑定到输入框的value
        props: ['value'],
        methods: {
            // 2.触发父组件上的input事件
            updateVal(val){
                this.$emit('input', val);
            }
        }
    });
     
    var app = new Vue({
        el: '#app',
        data(){
            price: ''
        },
        methods: {
            // 3.传递过来的值赋给父组件的price变量,实现了输入框到父元素的单向绑定
            onInput(val){
                this.price = val;
            }
        }
    })
</script>
  

通过上面的分析,默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event。所以当我们在一个自定义组件上使用v-model并不能实现双向绑定,因为自定的组件并没有默认的value和input事件,在使用时,我们需要按照上面那样显式的去声明定义这些东西。这时,model选项就派上用场了,在定义组件的时候,指定prop的值和监听的事件。

model中的prop若只有唯一属性,默认为value的存在,父组件可以省略
model中的event若只有唯一事件,默认为可触发的唯一事件,父组件可以省略
<script>
Vue.component('my-input',{
    model: {
        prop: 'uname',    //若要同上,此处为'value'   //声明父组件的uname(value)属性
        // 随便命名事件,对应下面$emit即可             
        event: 'changeXXX' //若要同上,此处为'input'  //声明父组件的changeXXX(input)事件
    },
    props: {
        uname: {
            type: String,
            default: 'tom'
        }
    },
    methods: {
        updateVal(val){
            this.$emit('changeXXX',val)
        }
    }
     template: `<input :value='uname' @input='updateVal($event.target.value)' type='text'></input>`,
})
    
    var app = new Vue({
        el: '#app',
        data{
            name: ''
        }
    })
</script>
完成上述操作后就可以直接使用v-model将实例中的变量和子组件的value进行绑定啦!

可以在html代码中直接使用
<my-input v-model="name" value="some value"></my-input>
<p>{{name}}</p>

等价于
相当于进行了下面的操作                 //下面这个是箭头表达式
<my-input :uname='name' @changeXXX='(val) => {name = val}' value='some value'></my-input>

箭头函数表达式的语法比普通函数表达式更简洁。

(参数1, 参数2, …, 参数N) =>{ return 表达式; }//箭头表达式
//ps:箭头函数是不能提升的,所以需要在使用之前定义。

组件-ref和$refs-不仅可以获取data还能调用方法

//console.log(this.$refs.hello.msg)获取本组件中ref="hello"的msg(data)属性
//console.log(this.$refs.testDom)获取本组件中ref="testDom"的内容
//父组件
<template>
  <div id="app">  
    <HelloWorld ref="hello"/> //子组件
    <button @click="getHello">获取helloworld组件中的值</button>
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  components: {
    HelloWorld
  },
  data() {
    return {}
  },
  methods: {
    getHello() {
      console.log(this.$refs.hello.msg)
    }
  }
};
</script>

//子组件HelloWorld
<template>
  <div>
      {{ msg }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: "hello world"
    }
  }
}
</script>


Vue管道-用于自定义函数执行的顺序,将最后执行的结果展示在界面上,相当于main函数

私有过滤器如下

{{ message | filterA('arg1', arg2) }}
filterA有3个参数,第一个默认是message
变量'arg1'是第二个参数
表达式arg2的返回值是第三个参数

语法:{{ message | filterA | filterB }}

从左到右顺序,前一个参数的值传给右边的表达式作为默认的第一个参数

<div id="app">
  {{ message | capitalize('!',label,1<2?true:false) | capitalize2}}
              //一共4个参数,其中第一个是message    //一个参数即默认,前一个的值
</div>
<script>
new Vue({
  el: '#app',
  data: {
    message: 'runoob',
     label:'———'
  },
  filters: {
    capitalize: function (value,value2,value3,value4) { 
        //value是message,value2是'!',value3是label,value4是1<2?true:false也就是true
      if (!value) return ''
      value = value.toString()
        console.log('capitalize1调用');
      		document.write(value4)
      return value.charAt(0).toUpperCase() + value.slice(1)+value2+value3+value4;
    },
       capitalize2: function (value) { //value是capitalize函数的返回值
      if (!value) return ''
      value = value.toString()
           console.log('capitalize2调用');
      return value.charAt(0)+value.charAt(1).toUpperCase() + value.slice(2);
    }
  }
})

全局过滤器-Vue.filter(过滤器名,处理函数)

image-20220426164428083

computed计算属性-初始化时会调用一次get()

一个computed的对象最多有一个set和get,最少有一个get

当唯一一个无参的getter函数内的变量发生改变时,就自动调用一次getter函数,也可以手动调用vm.对象

手写setter函数(有参数的)就行,给外部提供了可以调用的函数,调用一次执行一次,如下

使用vm.site会调用get()//默认的只有getter()。setter()要自己写
vm.site = '菜鸟教程 http://www.runoob.com';//这样可以传值到set()
computed: {
    site: {
      // getter    --只要是无参的函数(也只能有一个,必须有一个)就作为getter
      get: function () {
        return this.name + ' ' + this.url
      },
      // setter
      set: function (newValue) {
                              //newValue='菜鸟教程 http://www.runoob.com'
        var names = newValue.split(' ')
        this.name = names[0]
        this.url = names[names.length - 1]
      }
    }
  }

computed它依赖于缓存,它一开始先执行一次,然后只有当函数内的变量改变之后,才执行一次;而methods每次调用都会执行一次。

computed调用不加"()",methods调用必须要加"()",不然会当成data处理,若data没有则undefined

//使用computed的cnt一直是2,只执行了一次代码!只要message不改变,基于缓存
//而使用methods,每调用一次就会执行一次,cnt会一直加下去,结果没有变
<div id="app">
  <p>原始字符串: {{ message }}</p>
  <p>计算后反转字符串: {{ reversedMessage }}</p> 
  <p>计算后反转字符串: {{ reversedMessage }}</p>
  <p>使用方法后反转字符串: {{ reversedMessage2() }}</p>
  <p>使用方法后反转字符串: {{ reversedMessage2() }}</p>
</div>
<script>
var cnt=1;
var vm = new Vue({
  el: '#app',
  data: {
    message: 'Runoob!'
  },
  computed: {
    // 计算属性的 getter--无参的函数作为getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      cnt+=1;
      return cnt+this.message.split('').reverse().join('')
    }
  },
  methods: {
    reversedMessage2: function () {
      cnt+=1;
      return cnt+this.message.split('').reverse().join('')
    }
  }
})
</script>
输出结果:
原始字符串: Runoob!

计算后反转字符串: 2!boonuR

计算后反转字符串: 2!boonuR

计算后反转字符串: 2!boonuR

使用方法后反转字符串: 3!boonuR

使用方法后反转字符串: 4!boonuR

$event对象-后续继续了解-可选

<div id="app-5">
  <p>{{ message }}</p>
  <button v-on:click="add($event)">asdas</button>//$event传入了触发这个事件的对象
    //可以直接v-on:click="add"若本身无参,直接使用方法名,将默认传入$event
    //若本身有参,又需要event:v-on:click="add($event,a)"
</div>
<script>
    var app = Vue({
        el="app-5",
        methods:{
        add:function(e){  //若本身有参,又需要event:add:fuction(e,a)
        alert(e.target.tagName)//可以使用、修改这个对象本身的属性
    }
    }
    })
</script>

输入框input获取焦点:input对象.focus()。input对象通过DOM.getbyid那个获得,也可以通过传参获得

Vue自定义指令(全局定义只能一个,局部定义可以有多个)

例子:v-focus只需要定义focus,调用时使用v-focus

<div id="app">
  <p>页面载入时,input 元素自动获取焦点:</p>
  <input v-focus>
</div>

//全局定义,一次一个
<script>
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
  // 当绑定元素插入到 DOM 中。
  inserted: function (el) {  //此处el是DOM中使用了v-focus的对象,此处是input对象
    // 聚焦元素
    el.focus()      //相当于input对象.focus(),实现了input的聚焦
  }
})
</script>

//局部定义,一次可以定义多个·
<script>
// 创建根实例
new Vue({
  el: '#app',
  directives: {
    // 注册一个局部的自定义指令 v-focus
    focus: {
      // 指令的定义
      inserted: function (el) {
        // 聚焦元素
        el.focus()
      }
    }
    // 再注册一个局部的自定义指令 v-focus2
    focus2: {
      // 指令的定义
      inserted: function (el) {
        // 聚焦元素
        el.focus()
      }
    }
  }
})
</script>

自定义指令绑值-bind函数和binding.value

image-20220429111253064

这边的color是data()中的,'red'表示字符串,传入一个颜色进入自定义指令

image-20220429111157105

image-20220429111654741

自定义指令-update函数

image-20220429111909886

自定义指令简写-bind函数和update函数

当bind的语句和update相同的时候,我们可以直接使用简写

image-20220429113710211

等价于

image-20220429113745620

全局自定义指令-写在main.js中

image-20220429114144065

简写如下

image-20220429114046807

Vue周期图-钩子函数

生命周期图.png

lifecycle

     <script>
         //周期函数和data,methods,el同级
        var vm=new Vue({
            el: "#app",
            data: {},
            beforeCreate() {console.log("beforeCreate")},
            //中间过程:初始化->实例的data、el、methods、watch
            created() {console.log("created")},//初始化完成
            beforeMount() {console.log("beforeMount")},
            //中间过程:渲染到页面上->(data、methods) to el to page//内存中渲染至el,再和DOM替换el
            mounted() {console.log("mounted")},//渲染完成
            beforeUpdate() {console.log("beforeUpdate")},
            //中间过程:数据发生改变时,要同时更新页面的数据
            updated() {console.log("updated")},//更新完成
            beforeDestroy() {console.log("beforeDestroy")},
            //中间过程:销毁对象,解绑它的全部事件和指令监听器,如(v-if:变量=false导致的销毁)
            destroyed() {console.log("destroyed")},//销毁完成
            methods: {}
            });
    </script>
函数名称 版本 说明
beforeCreate 2.0+ vue实例创建初始化后,数据观测 (data observer) 和event/watch事件配置之前触发
created 2.0+ 在实例创建完成后被立即调用,此时实例已完成数据观测 (data observer),属性方法的运算,watch/event 事件回调的配置。然而,挂载阶段还没开始,$el 属性目前不可见
beforeMount 2.0+ 实例挂载开始之前被调用, render 函数首次被调用,该钩子在服务器端渲染期间不被调用
mounted 2.0+ 实例已挂载。mounted 不会承诺所有的子组件也都一起被挂载,如果你希望等到整个视图都渲染完毕再进行一些操作,请用 vm.$nextTick:mounted: function () {this.$nextTick(function () { // Code that will run only after the entire view has been rendered })}该钩子在服务器端渲染期间不被调用
beforeUpdate 2.0+ 数据更新时调用,发生在虚拟 DOM 打补丁之前,这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器,该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行
updated 2.0+ 数据更改会导致虚拟 DOM 重新渲染和打补丁,在这之后会调用updated钩子。updated 不会承诺所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,请用 vm.$nextTick :updated: function () {this.$nextTick(function () { // Code that will run only after the entire view has been re-rendere})} updated钩子被调用时,组件 DOM 已经更新,你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改实例中的状态属性,如果要相应状态改变,通常最好使用计算属性或 watcher
beforeDestroy 2.0+ 实例销毁之前调用。在这一步,实例仍然完全可用,该钩子在服务器端渲染期间不被调用
destroyed 2.0+ Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会接触绑定,所有的事件监听器会被移除,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用
activated 2.0+ 当某个组件使用了keep-alive组件缓存时,该组件激活时调用activated钩子,该钩子在服务器端渲染期间不被调用
deactivated 2.0+ 当某个组件使用了keep-alive组件缓存时,该组件停用时调用deactivated钩子,该钩子在服务器端渲染期间不被调用
errorCaptured 2.5.0+ 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播

this.$nextTick(函数)

一般来说函数内的语句从上到下按顺序执行,但是使用了这个方法之后,将某些代码推迟到updated之后执行。

image-20220428195711308

image-20220428195740439

指令钩子函数

钩子函数

指令定义函数提供了几个钩子函数(可选):

  • bind:只调用一次,指令第一次绑定到元素(还没有渲染到页面)时调用,比较常用。(自定义获取焦点无效)

  • inserted:元素渲染好了,插入到元素中。在表单获取焦点focus时使用。

  • update:当前元素渲染完成,绑定的值发生改变的时候触发。

  • componentUpdated:当前元素所在的区域全部渲染完成,绑定的值发生改变时触发。

  • unbind:只调用一次,指令与元素解绑时调用。

钩子函数参数

钩子函数的参数有:

  • el: 指令所绑定的元素,可以用来直接操作 DOM 。相当于外部传入了一个$event

  • binding
    一个对象,包含以下属性:
    • name: 指令名,不包括 v- 前缀。
    • value: 指令的绑定的最新的值, 例如: v-my-directive="1 + 1", value 的值是 2
    • oldValue: 指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression: 绑定值的表达式或变量名。 例如 v-my-directive="1 + 1" , expression 的值是 "1 + 1"
    • arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 "foo"
    • modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }
  • vnode: Vue 编译生成的虚拟节点 。--》虚拟节点就是在内存中渲染好的 el

  • oldVnode: 上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。

    但其实大多数情况 我们只希望节点在加载和更新时发生同样的事情,而忽略其它钩子函数,可以这么写

    <script>
    //唯一一个自定义匿名钩子函数,忽略其他钩子函数,简化代码
    //指令为v-color-swatch
    Vue.directive('color-swatch', function (el, binding) {
    	el.style.backgroundColor = binding.value
    })
    </script>
    

    指令钩子函数总结

    通过自定义指令,我们可以可选的编写钩子函数,见上钩子函数可以最多有4个参数,通过这四个参数可以对绑定了该指令的DOM元素进行操作

    <div id="app"  v-runoob:hello.a.b="message">
    </div>
    
    <script>
    Vue.directive('runoob', {
      bind: function (el, binding, vnode) {
        var s = JSON.stringify
        el.innerHTML =
          'name: '       + s(binding.name) + '<br>' +
          'value: '      + s(binding.value) + '<br>' +
          'expression: ' + s(binding.expression) + '<br>' +
          'argument: '   + s(binding.arg) + '<br>' +
          'modifiers: '  + s(binding.modifiers) + '<br>' +
          'vnode keys: ' + Object.keys(vnode).join(', ')
      }
    })
    new Vue({
      el: '#app',
      data: {
        message: '菜鸟教程!'vue
      }
    })
    </script>
    

    结果:

    name: "runoob"
    value: "菜鸟教程!"
    expression: "message"
    argument: "hello"
    modifiers: {"a":true,"b":true}
    vnode keys: tag, data, children, text, elm, ns, context, functionalContext, key, componentOptions, componentInstance, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce

Vue路由原理

Vue路由是hash地址和组件的对应关系!

hash地址是url种#开头的地址如:http://212.321.344.1/index.html#/head

/head就是hash地址,一般来说最好加上/,也可以不加

window.onhashchange事件是当url的hash地址发生了变化之后立即触发的事件,我们可以根据hash地址的不同,选择不同的组件进行展示

image-20220430085709665

image-20220430085441113

Vue-router路由,用于隐藏模块代码-简化代码

安装

image-20220430090019212

创建路由模块

image-20220430090111026

导入并挂载路由模块

image-20220430090621714

简单实例

a链接要加#,router-link不需要加#

Vue.js + vue-router 可以很简单的实现单页应用。

是一个组件,该组件用于设置一个导航链接,切换不同 HTML 内容。 to 属性为目标地址, 即要显示的内容。

作为的渲染,单击链接之后

中的to到路由表中查对应的组件,然后渲染到

当前点击的会加上样式 class ="router-link-exact-active router-link-active",


<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
 
<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/foo">Go to Foo</router-link>
      <!--等价于-->
     <a href="#/foo">Go to Foo</a>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>

<script>
// 0. 如果使用模块化机制编程,导入 Vue 和 VueRouter,要调用 Vue.use(VueRouter)
 
// 1. 定义(路由)组件。
//下面两个是组件配置对象
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
 
// 2. 定义路由(
// 每个路由应该映射一个组件。 其中"component" 可以是通过 Vue.extend() 创建的组件构造器,或者,只是一个组件配置对象。

//路由表:匹配path,渲染component
const routes = [      
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]
 
// 3. 创建 router 实例,然后传 `routes` 配置
//路由器实例化:
const router = new VueRouter({
  routes // (缩写)相当于 routes: routes
})
 
// 4. 创建和挂载根实例。
// 通过 router 配置参数,然后给对应的Vue实例注入路由
const app = new Vue({
  router //(缩写)相当于 router: router
}).$mount('#app')
 
// 现在,应用已经启动了!
</script>

路由重定向-redirect

image-20220430091905831

嵌套路由

image-20220430092408581

image-20220430092537218

children属性声明子路由规则

子路由不要加 / 斜杠

image-20220430092317057

默认子路由

image-20220430093124706

动态路由

当url会动态变化的时候,使用动态路由,使用冒号加变量名占位,如:id

image-20220430093831884

当点击对应的router-link后,组件Movie的原型this会多出来路由选项,占位符id会被赋值成对应的1,

简化了路由的代码,提高了复用性

image-20220430094123414

所以我们可以通过this.$route.params.id动态地获取路由参数,这里this可加可不加因为使用插值{{}}

image-20220430094517317

props路由动态传参,将path中自定义的变量传入组件

动态获取url中的数据传入子组件

props设置成true

image-20220430095039708

this.$route是路由的参数对象

通过this.$route.fullPath获取完整的url路径

在hash地址中/后面的参数项叫做“路径参数

通过this.$riute.params访问

在hash地址中?后面的参数项叫做“查询参数

通过this.$route.query访问

image-20220430095959937

声明式导航&编程式导航

image-20220430103454839

this.$router是路由的导航对象-拥有很多常用的编程式导航API

this.$router.push('hash地址')
this.$router.replace('hash地址')
this.$router.go(数值n)  若n超过上下限则原地不动

image-20220430104427775

image-20220430104347465

image-20220430104706830

导航守卫

image-20220430105012703

全局前置守卫-beforeEach

image-20220430105211122

image-20220430105410024

next函数的3种调用方式

image-20220430105913846

image-20220430110739135

image-20220430110425239

创建自定义组件-extend(),也可以使用之前的component

const Home = Vue.extend({和component一样的内容});

 注1:extend是构造一个组件的语法器. 你给它参数,他给你一个组件,然后这个组件
       你可以作用到Vue.component这个全局注册方法里,也可以在任意vue模板里使用car组件

  注2:也可以用以前的方式创建和获得组件,效果也是一样的
       Vue.component("button-counter", {...});//创建组件
   var ButtonCounter = Vue.component('button-counter');//获得组件

// 注册组件,传入一个扩展过的构造器-这里使用extend返回构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))

// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', { /* ... */ })


总结:extend和component作用基本相同,区别在于我们需不需要使用组件名称,不需要使用组件名称时,用extend会简便些;需要使用新的标签来定义组件时,那么就用component去创建组件;

但是!!!,extend必须要挂载,和对应的Vue实例对象绑定!!!

<div id="mount-point"></div>
<script>
    // 创建构造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')
</script>


// 结果如下:
<p>Walter White aka Heisenberg</p>

相关属性

接下来我们可以了解下更多关于 的属性。

to-必须有

表示目标路由的链接。 当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。

<!-- 字符串 -->
<router-link to="home">Home</router-link>
<!-- 渲染结果 -->
<a href="home">Home</a>

<!-- 使用 v-bind 的 JS 表达式 -->
<router-link v-bind:to="'home'">Home</router-link>

<!--  v-bind 缩写 -->
<router-link :to="'home'">Home</router-link>

<!-- 直接写路由表的匹配路径 -->
<router-link :to="{ path: 'home' }">Home</router-link>

<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

<!-- 带查询参数,下面的结果为 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>

tag

router-link默认渲染成a标签,tag可以选择渲染指定标签

<router-link to="/foo" tag="li">foo</router-link>
<!-- 渲染结果 -->
<li>foo</li>

active-class相当于class来用,但不能是class.[模糊匹配时]

设置 链接激活时使用的 CSS 类名。

<style>
   ._active{
      background-color : red;
   }
</style>
<p>
   <router-link v-bind:to = "{ path: '/route1'}" active-class = "_active">Router Link 1</router-link>
   <router-link v-bind:to = "{ path: '/route2'}" tag = "span">Router Link 2</router-link>
</p>

exact-active-class [精确匹配时]

配置当链接被精确匹配的时候应该激活的 class。可以通过以下代码来替代。

<p>
   <router-link v-bind:to = "{ path: '/route1'}" exact-active-class = "_active">Router Link 1</router-link>
   <router-link v-bind:to = "{ path: '/route2'}" tag = "span">Router Link 2</router-link>
</p>

关于active-class和exact-active-class

router-link 默认情况下的路由是模糊匹配

例如当前路径是 /article/1

会激活

但是这个 router-link 只有在当前路由被 “to” 全包含匹配时才会被激活 exact-active-class 中的 class

event

声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。

<router-link v-bind:to = "{ path: '/route1'}" event = "mouseover">Router Link 1</router-link>

replace-清空浏览history,相当于无痕浏览

设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),导航后不会留下 history 记录。

<router-link :to="{ path: '/abc'}" replace></router-link>

借鉴javascript的笔记对比:push()相当于window.history.forward()

获取当前页面URL:location.href

获取当前URL的路径:location.pathname

以下必须是在同一个页面跳转,而不是新建一个页面

从当前页面跳转到其他页面:window.location.assign("另一网址")

返回跳转之前的一个页面(若有):window.history.back()

返回跳转之后的一个页面(若有):window.history.forward()

访问顺序:A->B->C

A:back

B:当前页面

C:forward

使用window.history.go(数字)也可以实现。数字为正往后跳转,数字为负,往前跳转。

若数字为0,则表示自身,跳转到自身,相当于刷新

在A页面数字为2,则跳转到C,在B页面数字为1,则跳转到C

在C页面数字为-2,跳转到A,在B页面数字为-1,则跳转到A

append

设置 append 属性后,则在当前 (相对) 路径前添加基路径。

例如,我们从 /eth/login导航到一个相对路径 /eth/block,如果没有配置 append,则路径为 /block,如果配了,则为 /eth/block

<router-link to="block/" append>从login跳到同级的block路由</router-link>前面会加上/eth/

<!-- 如果现在路由为block,想跳到eth/: -->
<router-link to="../" append>回到上级eth路由</router-link>'/eth/../' 就是/eth

slot标签-可以接收任何类型、模板内容

slot标签用于子组件,作为一个插槽,父组件使用子组件时,子组件中间的内容会被传递到子组件,替换slot

父组件:
<template>
    <div>
      <div>大家好我是父组件</div>
      <myslot>
        <p>测试一下吧内容写在这里了能否显示</p>
      </myslot>
    </div>
</template>
//子组件myslot
<template>
  <div>
      <div>我是子组件</div>
      <slot></slot>     <!--p标签会替换该行-->
  </div>
</template>

若子组件没有slot标签的话,父组件中子组件标签的内容会被丢弃

父组件:
<template>
    <div>
      <div>大家好我是父组件</div>
      <myslot>
        <p>测试一下吧内容写在这里了能否显示</p>
          <!--由于子组件没有slot,所以p标签会被丢弃-->
      </myslot>
    </div>
</template>
//子组件myslot
<template>
  <div>
      <div>我是子组件</div>
  </div>
</template>

slot标签之间可以填写内容,当父组件没有任何内容时,默认使用slot标签的内容作为后备内容,若有,则优先使用父组件的内容。

父组件:
<template>
    <div>
      <div>大家好我是父组件</div>
      <myslot>
       <!--这里没有任何内容-->
      </myslot>
    </div>
</template>
//子组件myslot
<template>
  <div>
      <div>我是子组件</div>
      <slot>hhhhh</slot>     <!--则使用"hhhhh"代替-->
  </div>
</template>

slot-name属性-具体槽名-使用v-slot

当slot没有name属性的时候,默认name为defalut,当有的时候,父组件通过传入的内容会和slot的name一一对应。

剩下的没有name对应的内容,全部插入到默认的slot中去!

注意!

v-slot 只能添加在 <template> 上或组件中

缩写:v-slot:header 可以使用#header //使用"#"等价于v-slot

//父组件
<template>
  <myslot>
    <div>大家好我是父组件</div>
    <template v-slot:header>
      <h1>Here might be a page title</h1>
    </template>

    <p>A paragraph for the main content.</p>
    <p>And another one.</p>

    <template v-slot:footer>
      <p>Here's footer info</p>
    </template>
  </myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
  }
</script>

//子组件myslot
<template>
  <div class="container">
    <header>
      <slot name="header"></slot><!--v-slot:header的模板位置-->
    </header>
    <main>
      <slot></slot>   <!--这里是默认的slot,没匹配到的就放这里-->
    </main>
    <footer>
      <slot name="footer"></slot><!--v-slot:footer的模板位置-->
    </footer>
  </div>
</template>
结果:
Here might be a page title     //header
大家好我是父组件                  //默认
A paragraph for the main content.//默认

And another one.              //默认

Here's footer info            //footer

之前提到了后备内容hhhhhh是个静态的,写死的内容。外面也可以使用动态的方法。

//子组件
<template>
  <div>
    <span>
      <slot>{{user.firstName}}</slot>//直接使用子组件的dataz
    </span>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        user:{
          firstName:'gerace',
          lastName:'haLi'
        }
      }
    }
  }
</script>

但是父组件不能使用子组件的属性,因为作用域不同,以下代码运行会报错!

//父组件
<template>
  <myslot>{{ user.firstName }}</myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
  }
</script>

那么怎样使得父组件的内容里可以使用子组件的数据和方法呢?

首先我们要对子组件先进行修改!

通过v-bind将子组件的对象user和自定义的user属性绑定,使得父组件可以通过自定义的user属性获得子组件的user对象!

//子组件
<template>
  <div>
    <span>
      <slot v-bind:user="user">
        {{ user.lastName }}
      </slot>
    </span>
  </div>
</template>
<script>
  export default {
    data () {
      return {
        user:{
          firstName:'gerace',
          lastName:'haLi'
        }
      }
    }
  }
</script>

若slot是一个默认的(没有name,不是具名插槽),则父组件可以使用以下方法获取。

slotProps是一个自己取的对象名,通过slotProps可以获取子组件的属性
<template>
  <myslot>
      <template v-slot:default="slotProps">
      {{ slotProps.user.firstName }}
      </template>
  </myslot>
</template>

仅仅只有默认slot的时候可以使用缩写

<template>
  <myslot v-slot="slotProps">
     {{ slotProps.user.firstName }}
  </myslot>
</template>

有具体槽名的时候,有name的时候,默认slot不可以使用缩写

具体槽名的调用方法如下:

<template>
  <myslot>
      <template v-slot:default="slotProps">//不要使用缩写!!!
      {{ slotProps.user.firstName }}
      </template> 
      <template v-slot:header="slotProps">
        {{ slotProps.userData.firstName }}
      </template>
      <template v-slot:footer="slotProps">
        {{ slotProps.hobbyData.fruit }}
      </template>
  </myslot>
</template>

具体槽名也可以缩写!!!省掉调用对象!

<template>
  <myslot>
      <template #header="{userData}">
        {{ userData.firstName }}
      </template>
      <template #footer="{hobbyData}">
        {{ hobbyData.fruit }}
      </template>
  </myslot>
</template>
等价于
<template>
  <myslot>
      <template v-slot:header="{userData}">
        {{ userData.firstName }}
      </template>
      <template v-slot:footer="{hobbyData}">
        {{ hobbyData.fruit }}
      </template>
  </myslot>
</template>

作用域插槽

这边的obj名字最好使用scope,比较规范,这属于作用域插槽

image-20220429103951444

dataset-切换界面

常用于切换页面,内置data-(attribute)属性

使用e.currentTarget.dataset.cur获得data-cur的值

e.currentTarget获取的是哪个view触发了单击事件,传入这个对象

<tools v-if="PageCur == 'mrxc'"></tools>
<user v-if="PageCur == 'grzx'"></user>
<element v-if="PageCur == 'xcsh'"></element>
<!--v-if根据PageCur的值确定显示情况-->

<view class="action" @click="NavChange" data-cur="xcsh">
				
</view>
<view class="action" @click="NavChange" data-cur="grzx">
				
</view>
<view class="action" @click="NavChange" data-cur="mrxc">
				
</view>
<script>
    export default {
	components: {
		tools,
		user,
		element
	},
	data() {
		return {
			PageCur: 'mrxc'
		};
	},
	methods: {
		//获取data-cur
		NavChange: function(e) {
			this.PageCur = e.currentTarget.dataset.cur;
		}
        //上下两个都行!!!
        //获取data-index
        test(e){
			console.log(e.target.dataset.index);
		}
	}
};
</script>

target--(捕捉和冒泡会影响触发事件的对象组件)

触发事件的源组件。

属性 类型 说明
id String 事件源组件的id
dataset Object 事件源组件上由data-开头的自定义属性组成的集合

currentTarget--常用

事件绑定的当前组件。

属性 类型 说明
id String 当前组件的id
dataset Object 当前组件上由data-开头的自定义属性组成的集合

扩展运算符 - ...

详见https://blog.csdn.net/weixin_44682587/article/details/113740701

//1.依次遍历数组
iClick() {
	let iArray = ['1', '2', '3'];
	console.log(...iArray);
	// 打印结果  1 2 3
},
//2.扩展数组
iClick3() {
	let iArray = ['1', '2', '3'];
    let bigArray = ['0', ...iArray, '4'];
	console.log(bigArray);
	// 打印结果  ["0", "1", "2", "3", "4"]
}
//3、数组赋值/获取元素
iClick8() {
	const [first, ...rest] = [1, 2, 3, 4, 5];
	console.log(first);
	// 打印结果 1
	console.log([...rest]);
	// 打印结果 [2, 3, 4, 5]
	
	const [one, ...last] = ["foo"];
	console.log(one);
	//打印结果 foo
	console.log([...last]);
	//打印结果 []
}

//3.数组合并
iClick7() {
	var arr1 = [0, 1, 2];
	var arr2 = [3, 4, 5];
    //方法1:
	//console.log([...arr1, ...arr2]);
    //方法2:
  //  arr1.push([{...arr2}])
    
	//  打印结果 [0, 1, 2, 3, 4, 5]
},
//4、字符串转化成数组
    iClick9() {
	let iString = 'woshizhongguoren';
	console.log([...iString]);
	//  打印结果 ["w", "o", "s", "h", "i", "z", "h", "o", "n", "g", "g", "u", "o", "r", "e", "n"]
},
//5.map
iClick10() {
	let map = new Map([
	[1, 'one'],
	[2, 'two'],
	[3, 'three'],
	]);
	let arr = [...map.keys()];
	console.log(arr);
	//  打印结果 [1, 2, 3]
}
//6.用于一次传入多个参数
iClick4() {
	let iArray = ['1', '2', '3'];
	this.hanshu(...iArray);//注意传的时候,就要三个点
},
hanshu(...iArray) {
	let ooo = 1;
	console.log(...iArray);
	//  打印结果 1 2 3
}
//7.字典遍历
//直接遍历字典会报错!
iClick11() {
	let obj = {
		name: 'zhh',
		age: '20'
	}
	console.log([...obj]);
	}
}
//但是有别的方法!使它变成一个数组
test() {
	let obj = [{name: 'zhh'},{age: '20'}];
        //console.log(...obj);每次遍历出来的都是字典对象
		//console.log([...obj]);每次遍历出来的都是数组对象
}

//8.修改属性-通过覆盖
method2() {
	let a = {name: 'zhh', age: 18, id: 10};
	//先拿到a, 后面的name:zhh1,把 a 中name 的值替换掉了
	let c = {...a, name: 'zhh1'};   //...a必须在前面,使得后面的name覆盖前面的name
	console.log(c);
	// 打印结果  {name: "zhh1", age: 18, id: 10}
}

Ajax

https://www.runoob.com/vue2/vuejs-ajax-axios.html

npm install axios

Vue.js 2.0 版本推荐使用 axios 来完成 ajax 请求。

Axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中。

等价于uniapp中的uni.request

get实现

// 直接在 URL 上添加参数 ID=12345
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
 
// 也可以通过 params 设置参数:
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

Post实现

axios.post('/user', {
    firstName: 'Fred',        // 参数 firstName
    lastName: 'Flintstone'    // 参数 lastName
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

同时执行多个并发请求

function getUserAccount() {
  return axios.get('/user/12345');
}
 
function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 两个请求现在都执行完成
  }));

请求方法别名-简化代码

注意:在使用别名方法时, url、method、data 这些属性都不必在配置中指定。

axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])

axios请求的响应内容

{
  // `data` 由服务器提供的响应
  data: {},

  // `status`  HTTP 状态码
  status: 200,

  // `statusText` 来自服务器响应的 HTTP 状态信息
  statusText: "OK",

  // `headers` 服务器响应的头
  headers: {},

  // `config` 是为请求提供的配置信息
  config: {}
}

配置全局默认值

axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

Vuex

//写在main.js中,作为全局的数据支持
import { createApp } from 'vue'
import { createStore } from 'vuex'

// 创建一个新的 store 实例
const store = createStore({
  state () {
    return {
      count: 0,
      todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
    }
  },
  mutations: {   //等价于method【同步】
    increment (state) {
      state.count++
    }
  },
  getters: {    //等价于computed
    doneTodos: (state) => {
      return state.todos.filter(todo => todo.done)//筛选出每一项的done属性为true的行
    }
  }
   actions:{  //等价于method【异步】
    
    //getData() 和 getOtherData()是同步函数
    //异步函数用于处理同步函数或其他逻辑
      async actionA ({ commit }) {
        commit('gotData', await getData())
      },
      async actionB ({ dispatch, commit }) {
        await dispatch('actionA') // 等待 actionA 完成
        commit('gotOtherData', await getOtherData())
      }
	}
})

const app = createApp({ /* 根组件 */ })

//将store作为根目录的全局变量
// 将 store 实例作为插件安装
app.use(store)
//其他文件中使用this.$store即可



//外界触发通过commit触发mutations中的函数
methods: {
  increment() {
    this.$store.commit('increment')
      //外界获取store.state的值!
    console.log(this.$store.state.count)
  }
}

若不想store设置成全局,仅仅局部的话,见下图,直接挂载到vue实例中

image-20220407100708455

外界实时获取store.state的数据使用计算属性更好!

const Counter = {
  template: `<div>{{ count }}</div>`,
  //计算属性依赖于缓存
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

mapState 辅助函数

可以直接使用store中的state

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias【自定义的变量名】: 'count',//直接使用'count'更简洁

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

我们可以使用mapState的字符串数组形式直接导入store中的state

image-20220407101252272

对象展开运算符...

由于mapState 函数返回的是一个对象。所以直接用于computed属性时,不合适,所以使用对象展开运算符,将mapState对象内的其他方法进行展开最为合适!!!

若computed计算属性只有mapState,最好也要加上

computed: {
  localComputed () { /* ... */ },
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState({//将mapState内的方法进行展开
    // ...
  })
}

Getter

const store = createStore({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: (state) => {
       //返回todo.done为true的todo记录
      	return state.todos.filter(todo => todo.done)
    },
  		// 返回满足条件的记录个数
  	
      
  },
        // 返回todo.id等于id的todo记录
  	getTodoById: (state) => (id) => {
    	return state.todos.find(todo => todo.id === id)
  }
}

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

store.getters.doneTodosCount // -> 1

store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

mapGetters 辅助函数-同上

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
      
  //若把 `this.doneTodosCount` 映射为 `this.$store.getters.doneTodosCount`
  //若把 `this.anotherGetter` 映射为 `this.$store.getters.anotherGetter`
      //全使用原来的名字!
  //使用字符串数组的形式
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  
     ...mapGetters({
      //若想换个变量名,则不使用字符串数组形式
  	// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
  		doneCount: 'doneTodosCount'
	})

      
      
     
  }
}

mutations-必须是同步函数 !!!-用于修改state

绝对不能有回调/异步函数,因为这会导致devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的!!!

触发:store.commit('increment')//调用同步函数

或者

const store = createStore({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})

提交载荷(Payload)

// mapMutations 也支持载荷:

store.commit 传入额外的参数,即 mutation 的载荷(payload)

mutations: {
  increment (state, n) {
    state.count += n
  }
}

store.commit('increment', 10)

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:

// ...
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
// 以载荷形式分发
store.commit('increment', {
  amount: 10
})

// 以对象形式分发
//将整个对象作为payload进行提交!内部函数代码不用改变
store.commit({
  	type: 'increment',
  	amount: 10
})


mapMutations 辅助函数-同上

你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
        // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
      'increment', 

      // `mapMutations` 也支持载荷:
      'incrementBy' 
     // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
      //若要改名字则单独拿出来,不用数组形式
    ...mapMutations({
      add: 'increment' 
// 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
}

Action-异步函数-主要用于派发任务-业务逻辑

mutation的函数都是同步函数,store.commit('increment')触发

action的函数都是异步函数,store.dispatch('increment')触发

action内的异步函数可能会调用同步函数

Actions 支持同样的载荷方式和对象方式进行分发:

// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

mapActions 辅助函数-同上

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

组合Action实现复杂的流程

https://vuex.vuejs.org/zh/guid-e/actions.html#组合-action

store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise:

// 假设 getData() 和 getOtherData() 返回的是 Promise


//getData() 和 getOtherData()是同步函数
actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

modules

const moduleA = {
  state: {
      count:3
  },
  mutations: {
     increment (state) {
         state.count++
      }
  },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: {
      Counts:30
  },
  mutations: { ... },
  actions: { ... }
}

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a.count // -> moduleA 的状态
store.state.b.Counts // -> moduleB 的状态

模块动态注册-store.registerModule

import { createStore } from 'vuex'

const store = createStore({ /* 选项 */ })

// 注册模块 `myModule`
store.registerModule('myModule', {
  // ...
})
// 注册嵌套模块 `nested/myModule`
store.registerModule(['nested', 'myModule'], {
  // ...
})

之后就可以通过 store.state.myModulestore.state.nested.myModule 访问模块的状态。

模块动态注册功能使得其他 Vue 插件可以通过在 store 中附加新模块的方式来使用 Vuex 管理状态。例如,vuex-router-sync 插件就是通过动态注册模块将 Vue Router 和 Vuex 结合在一起,实现应用的路由状态管理。

你也可以使用 store.unregisterModule(moduleName) 来动态卸载模块。注意,你不能使用此方法卸载静态模块(即创建 store 时声明的模块)。

注意,你可以通过 store.hasModule(moduleName) 方法检查该模块是否已经被注册到 store。需要记住的是,嵌套模块应该以数组形式传递给 registerModulehasModule,而不是以路径字符串的形式传递给 module。

保留 state

在注册一个新 module 时,你很有可能想保留过去的 state,例如从一个服务端渲染的应用保留 state。你可以通过 preserveState 选项将其归档:store.registerModule('a', module, { preserveState: true })

当你设置 preserveState: true 时,该模块会被注册,action、mutation 和 getter 会被添加到 store 中,但是 state 不会。这里假设 store 的 state 已经包含了这个 module 的 state 并且你不希望将其覆写。

模块调用根状态-rootState-rootGetters

const moduleB = {
    namespaced: true,
    modules: {
        subModule: {
            namespaced: true,
            state: {
                
            },
            mutations: {
                login () {}
            },
            getters: {
              login () {}  
            },
            actions: {
              login () {}  
            }
        }
    },
    state: {
        count: 8
    },
    mutations: {
        
    },
    getters: {
        someGetter (state, getters, rootState, rootGetters) {
            rootState.count;//这边是根节点的state的count=2
            state.count;//这边的是本地moduleB的state.count=8
        }
    },
    actions: {
        someAction({ dispatch, commit, getters }) {
            
        }
    }
}

const store = new Vuex.Store({
    modules: {
        a: moduleA,
        b: moduleB
    },
    state: {
        count: 2
    },
    mutations: {
        
    },
    getters: {
        
    },
    actions: {
        
    }
})

命名空间 -同上例结合

所有的模板下的mutation、getter、action、state这些都会被集成到被引用的store实例中作为全局变量

若不设命名空间,则调用上面的a模板的increment方法,只需要

store.commit('increment')即可

若设了命名空间 namespaced: true,则函数调用的路径改变

const moduleA = {
  namespaced: true,
  state: {
      count:3
  },
  mutations: {
     increment (state) {
         state.count++
      }
  },
  actions: { ... },
  getters: { ... }
}
//则store.commit('a/increment')才能使用a的方法
//store.dispatch('a/xxxx')
//store.getters['a/zzz']

// b模板下又嵌套了subModule模板   
const moduleB = {
    namespaced: true,
    modules: {
        subModule: {
            namespaced: true,
            state: {
                
            },
            mutations: {
                login () {}
            },
            getters: {
              login () {}  
            },
            actions: {
              login () {}  
            }
        }
    },
    state: {
        count: 8
    },
    mutations: {
        
    },
    getters: {
        
    },
    actions: {
        
    }
}
//则store.commit('b/subModule/login');
//store.dispatch('b/subModule/login');
//store.getters['b/subModule/login'];

由于命名空间的加入使得,当使用 mapStatemapGettersmapActionsmapMutations 这些函数来绑定带命名空间的模块时,写起来可能比较繁琐:

computed: {
  ...mapState({
    a: state => state.some.nested.module.a,
    b: state => state.some.nested.module.b
  })
},
methods: {
  ...mapActions([
    'some/nested/module/foo', // -> this['some/nested/module/foo']()
    'some/nested/module/bar' // -> this['some/nested/module/bar']()
  ])
}

对于这种情况,你可以将模块的空间名称字符串作为第一个参数传递给上述函数,这样所有绑定都会自动将该模块作为上下文。于是上面的例子可以简化为:

computed: {
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo', // -> this.foo()
    'bar' // -> this.bar()
  ])
}

createNamespacedHelpers

还可以通过使用 createNamespacedHelpers 创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:

import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')

export default {
  computed: {
    // 在 `some/nested/module` 中查找
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
  },
  methods: {
    // 在 `some/nested/module` 中查找
    ...mapActions([
      'foo',
      'bar'
    ])
  }
}

在带命名空间的模块内访问全局内容(Global Assets)

第一个参数为方法名字,第二个参数为payload,第三个参数{ root: true }固定,默认为false所以缺省了

//模板代码
//本地
dispatch('someOtherAction') // -> 'foo/someOtherAction'
//调用根
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
//本地
commit('someMutation') // -> 'foo/someMutation'
//调用根
commit('someMutation', null, { root: true }) // -> 'someMutation'

组合式API

可以通过调用 useStore 函数,来在 setup 钩子函数中访问 store。这与在组件中使用选项式 API 访问 this.$store 是等效的。

import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()
  }
}

访问 State 和 Getter

为了访问 state 和 getter,需要创建 computed 引用以保留响应性,这与在选项式 API 中创建计算属性等效。

import { computed } from 'vue'
import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()

    return {
      // 在 computed 函数中访问 state
      count: computed(() => store.state.count),

      // 在 computed 函数中访问 getter
      double: computed(() => store.getters.double)
    }
  }
}

访问 Mutation 和 Action

import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()

    return {
      // 使用 mutation
      increment: () => store.commit('increment'),

      // 使用 action
      asyncIncrement: () => store.dispatch('asyncIncrement')
    }
  }
}

时间处理库dayjs

image-20220426165130891

Ajax

axios库

npm i axios -S

image-20220426171500257

基础语法:

image-20220426171536426

image-20220426172019849

解构赋值直接获得data

image-20220426194626898

image-20220426194906653

image-20220426195052172

把axios挂载到Vue原型上

APP.vue:

image-20220429223655762

今后所有的组件都不用再导入axios库了,使用的时候直接使用this.$http,这里的$http是变量名,随便取。

还可以在APP.vue中设置axios默认的访问根路径,其他组件使用的时候直接写相对路径即可。

image-20220429224007791

CSS/LESS

局部css/less-scoped

在Vue中,若没有加scoped的话,默认会编译成全局样式,若加了,则在他所属的.vue文件生效

/deep/ 穿透样式

当使用第三方组件库的时候,如果有修改第三发组件库默认样式的需求,那么就会用到/deep/

在父组件中编写css/less的时候在选择器之前加上 /deep/则会去选择子组件的元素

<script lang="less">
/deep/ h5{
    color:pink;
}
</script>

标签:...,Vue,笔记,state,组件,data,store
From: https://www.cnblogs.com/lost-ways/p/17459558.html

相关文章

  • uniCloud笔记
    uniCloud笔记结合:uni-admin实现后台的云管理,schema2code辅助自动生成代码(只需要定义好表结构)云函数云函数,是将本地写好的函数上传到云端,在云端的node.js的环境中运行。可以在本地的页面中在生命周期函数(钩子函数)中调用云函数如下://在组件/页面加载时,调用云函数的回调函数on......
  • Vue-Cli笔记
    Vue-Cli笔记新手上路在创建模式的时候,选择最后一个模式:自定义模式,创建项目,只需勾选下图3个配置,使用空格进行选择和不选择。然后选择vue版本2.x在选择css预编译中选择less最后选择是否将babel、Eslint等文件放到一个独立的文件中或放入package.json,我们选择第一项独立的文......
  • javascript笔记
    javascript笔记获得焦点onfocus,失去焦点onblurisNaN()判断是非数字undefined和数字相加最后的结果是NaNnull和数字相加最后的结果是数字typeof空格变量名或typeof(变量名)可以检测变量的类型parseInt('120.8px')最后的结果是120->数字;自动去掉px......
  • Vue自定义指令-让你的业务开发更简单
    1、使用场景在日常开发中,我们会将重复代码抽象为一个函数或者组件,然后在需要时调用或者引入。但是,对于某些功能,这种方法可能不够优雅或者不够灵活。例如,我们可能需要在DOM元素上添加一些自定义属性或者绑定一些事件,这些操作可能难以通过函数或组件来实现。这时,自定义指令就派上用......
  • 【VUE】Vue事件与表单处理02
    一、事件与表单处理1、v-on监听事件<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"......
  • Vue router 二级默认路由设置
    一、起因打开默认地址/(http://localhost:5432/),home页面有空白,因为没有指定默认打开的子页。//router.jsexportconstconstantRoutes=[{path:'/',component:()=>import('@/views/MainView'),name:'Index',met......
  • Java官方笔记7接口
    接口接口只能包含:constants,methodsignatures(abstract),defaultmethods,staticmethods,andnestedtypes方法体只存在于:defaultmethodsandstaticmethods接口不能实例化,只能被类实现,或者被其他接口继承(接口可以多继承)。定义接口:publicinterfaceOperateCar{/......
  • 【VUE】Vue 快速入门 笔记基础01
    一、vue相关了解1、概述Vue.js是一种流行的JavaScript框架,用于构建响应式、交互式的前端Web界面。它采用了基于组件的开发模式,允许在单个页面中使用多个可重用的组件,提高了代码的复用性和维护性。只关心视图层,自底向上.遵守SOC关注点分离原则(术有专攻,只关注一点)HTML+CSS......
  • 《深入理解Spring Cloud与微服务构建》学习笔记(二十)~配置中心Spring Cloud Config
    本例重新创建项目,构建一个空的mavan工程。一、ConfigServer从本地读取配置文件 新建一个moudleconfig_server,pom添加依赖1.2.<groupId>org.springframework.cloud</groupId>3.<artifactId>spring-cloud-config-server</artifactId>4.</dependency>启动类添加......
  • vue之三种与后端交互的方式
    目录一、vue与后端交互之Ajax情况一:出现了跨域问题前端:index.html后端:main.py情况二:解决了跨域问题前端:index.html二、vue与后端交互之fetch简介fetch介绍后端:main.py前端:index.html三、vue与后端交互之axios1.简介html前端一、vue与后端交互之Ajax情况一:出现了跨域问题前端:in......