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特性
- 数据驱动视图
- 双向数据绑定
MVVM
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的作用
随便加!就是个包裹作用!,不影响程序运行,不会渲染到页面上
除了#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
some
every-返回布尔值【判断所有的情况】
filter-过滤出所有为true的数据集合
reduce-累加
缩写
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
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>
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
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-{
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>
事件修饰符
修饰符是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.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属性
动态组件方式每次发生组件切换,旧的组件就会被销毁,新的组件就会被创建
使用keep-alive保持状态
保持组件在被销毁的时候,不被销毁
deactivated和activated生命周期函数
keep-alive的include和exclude属性
默认是将keep-alive的所有子标签做缓存表示,但可以设置include属性和exclude属性,只能二选一,看实际情况。多个组件之间用逗号分割
Vue-组件-模板-自己DIY-简化代码
注册全局组件和局部组件
定义名为 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-可以是任何类型(String
、Number
、Object
、Boolen
、Array
等)
<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,后面有例子
<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
自定义组件实现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(过滤器名,处理函数)
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
这边的color是data()中的,'red'表示字符串,传入一个颜色进入自定义指令
自定义指令-update函数
自定义指令简写-bind函数和update函数
当bind的语句和update相同的时候,我们可以直接使用简写
等价于
全局自定义指令-写在main.js中
简写如下
Vue周期图-钩子函数
<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之后执行。
指令钩子函数
钩子函数
指令定义函数提供了几个钩子函数(可选):
-
bind
:只调用一次,指令第一次绑定到元素(还没有渲染到页面)时调用,比较常用。(自定义获取焦点无效) -
inserted
:元素渲染好了,插入到元素中。在表单获取焦点focus时使用。 -
update
:当前元素渲染完成,绑定的值发生改变的时候触发。 -
componentUpdated
:当前元素所在的区域全部渲染完成,绑定的值发生改变时触发。 -
unbind
:只调用一次,指令与元素解绑时调用。
钩子函数参数
钩子函数的参数有:
-
el: 指令所绑定的元素,可以用来直接操作 DOM 。相当于外部传入了一个$event
-
- binding
- 一个对象,包含以下属性:
- name: 指令名,不包括
v-
前缀。 - value: 指令的绑定的最新的值, 例如:
v-my-directive="1 + 1"
, value 的值是2
。 - oldValue: 指令绑定的前一个值,仅在
update
和componentUpdated
钩子中可用。无论值是否改变都可用。 - 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: 上一个虚拟节点,仅在
update
和componentUpdated
钩子中可用。但其实大多数情况 我们只希望节点在加载和更新时发生同样的事情,而忽略其它钩子函数,可以这么写
<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地址的不同,选择不同的组件进行展示
Vue-router路由,用于隐藏模块代码-简化代码
安装
创建路由模块
导入并挂载路由模块
简单实例
a链接要加#,router-link不需要加#
Vue.js + vue-router 可以很简单的实现单页应用。
从
当前点击的
<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
嵌套路由
children属性声明子路由规则
子路由不要加 / 斜杠
默认子路由
动态路由
当url会动态变化的时候,使用动态路由,使用冒号加变量名占位,如:id
当点击对应的router-link后,组件Movie的原型this会多出来路由选项,占位符id会被赋值成对应的1,
简化了路由的代码,提高了复用性
所以我们可以通过this.$route.params.id动态地获取路由参数,这里this可加可不加因为使用插值{{}}
props路由动态传参,将path中自定义的变量传入组件
动态获取url中的数据传入子组件
props设置成true
this.$route是路由的参数对象
通过this.$route.fullPath获取完整的url路径
在hash地址中/后面的参数项叫做“路径参数”
通过this.$riute.params访问
在hash地址中?后面的参数项叫做“查询参数”
通过this.$route.query访问
声明式导航&编程式导航
this.$router是路由的导航对象-拥有很多常用的编程式导航API
this.$router.push('hash地址')
this.$router.replace('hash地址')
this.$router.go(数值n) 若n超过上下限则原地不动
导航守卫
全局前置守卫-beforeEach
next函数的3种调用方式
创建自定义组件-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
会激活
但是
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
之前提到了后备内容
//子组件
<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,比较规范,这属于作用域插槽
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实例中
外界实时获取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
对象展开运算符...
由于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.myModule
和 store.state.nested.myModule
访问模块的状态。
模块动态注册功能使得其他 Vue 插件可以通过在 store 中附加新模块的方式来使用 Vuex 管理状态。例如,vuex-router-sync
插件就是通过动态注册模块将 Vue Router 和 Vuex 结合在一起,实现应用的路由状态管理。
你也可以使用 store.unregisterModule(moduleName)
来动态卸载模块。注意,你不能使用此方法卸载静态模块(即创建 store 时声明的模块)。
注意,你可以通过 store.hasModule(moduleName)
方法检查该模块是否已经被注册到 store。需要记住的是,嵌套模块应该以数组形式传递给 registerModule
和 hasModule
,而不是以路径字符串的形式传递给 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'];
由于命名空间的加入使得,当使用 mapState
、mapGetters
、mapActions
和 mapMutations
这些函数来绑定带命名空间的模块时,写起来可能比较繁琐:
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
Ajax
axios库
npm i axios -S
基础语法:
解构赋值直接获得data
把axios挂载到Vue原型上
APP.vue:
今后所有的组件都不用再导入axios库了,使用的时候直接使用this.$http,这里的$http是变量名,随便取。
还可以在APP.vue中设置axios默认的访问根路径,其他组件使用的时候直接写相对路径即可。
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