vue笔记
1.基本语法
实例
<div id="app">
<h2>{{message}}</h2>
</div>
const app = new Vue({
el:'#app',
data:{
message:'你好啊'
}
})
1.1. v-for 遍历
<li v-for="item in movies">{{item}}</li>
data:{
movies:['猩球崛起','盗梦空间','大话西游','速度与激情']
}
1.2. 插值的操作
<div id="app">
<h2>{{message}}</h2>
<h2 v-once>{{message}}</h2>
<h2 v-text="message">, 李银河!</h2>
</div>
<div id="app" v-cloak>
<h2>{{message}}</h2>
</div>
const app = new Vue({
el:'#app',
data:{
message:'你好啊',
url: '<a href="http://www.baidu.com">百度一下</a>',
}
})
1.3. v-bind 事件绑定 (语法糖 : :)
动态绑定属性,v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值
语法:
- 基本使用:
<img v-bind:src="imgURL" alt="">
<a v-bind:href="aHref">百度一下</a>
data: {
imgURL:'https://img11.360buyi.webp',
aHref: 'http://www.baidu.com'
}
- 动态绑定class(对象语法)
// 语法:<h2 v-bind:class="{key1: value1, key2: value2}">{{message}}</h2>
<h2 class="title" v-bind:class="{active: isActive, line: isLine}">{{message}}</h2>
<h2 class="title" v-bind:class="getClasses()">{{message}}</h2>
<button v-on:click="btnClick">按钮</button>
data: {
message: '你好啊',
isActive: true,
isLine: true
},
methods: {
btnClick: function () {
this.isActive = !this.isActive
},
getClasses: function () {
return {active: this.isActive, line: this.isLine}
}
}
- 动态绑定style(对象语法)
// 语法:<h2 :style="{key(属性名): value(属性值)}">{{message}}</h2>
<h2 :style="{fontSize: finalSize + 'px', backgroundColor: finalColor}">{{message}}</h2>
<h2 :style="getStyles()">{{message}}</h2>
data: {
message: '你好啊',
finalSize: 100,
finalColor: 'red',
},
methods: {
getStyles: function () {
return {fontSize: this.finalSize + 'px', backgroundColor: this.finalColor}
}
}
1.4. v-on 事件监听(语法糖: @)
语法:<button @click=“btn2Click”>按钮2
- 基本使用
<h2>{{counter}}</h2>
<button v-on:click="increment">+</button>
<button @click="decrement">-</button>
data: {
counter: 0
},
methods: {
increment() {
this.counter++
},
decrement() {
this.counter--
}
}
- v-on 的修饰符
<!--1. .stop修饰符的使用 阻止事件冒泡-->
<div @click="divClick">
aaaaaaa
<button @click.stop="btnClick">按钮</button>
</div>
<!--2. .prevent修饰符的使用 阻止默认响应-->
<br>
<form action="baidu">
<input type="submit" value="提交" @click.prevent="submitClick">
</form>
<!--3. .监听某个键盘的键帽-->
<input type="text" @keyup.enter="keyUp">
<!--4. .once修饰符的使用-->
<button @click.once="btn2Click">按钮2</button>
methods: {
btnClick() {
console.log("btnClick");
},
divClick() {
console.log("divClick");
},
submitClick() {
console.log('submitClick');
},
keyUp() {
console.log('keyUp');
},
btn2Click() {
console.log('btn2Click');
}
}
1.5. 条件判断
- v-if 的使用
<h2 v-if="isShow">{{message}}</h2>
data: {
message: '你好',
isShow: true
}
- v-if 和 v-else 的使用
<h2 v-if="isShow">{{message}}</h2>
<h1 v-else>isShow为false时,显示我</h1>
data: {
message: '你好',
isShow: true
}
- v-show 的使用
<!--v-if: 当条件为false时, 包含v-if指令的元素, 根本就不会存在dom中-->
<h2 v-if="isShow" id="aaa">{{message}}</h2>
<!--v-show: 当条件为false时, v-show只是给我们的元素添加一个行内样式: display: none-->
<h2 v-show="isShow" id="bbb">{{message}}</h2>
data: {
message: '你好啊',
isShow: true
}
1.6. 循环遍历
- v-for遍历数组
<!-- 1.在遍历的过程中,没有使用索引值(下标值) -->
li v-for="item in names">{{item}}</li>
<!-- 2.在遍历的过程中,获取索引值 -->
<li v-for="(item,index) in names">{{index+1}}.{{item}}</li>
data: {
names: ['Joe','Kobe','James','Curry']
}
- v-for遍历对象
<!-- 1.在遍历对象过程中,如果只是获取一个值,那么获取到的就是value -->
<li v-for="item in info">{{item}}</li>
<!-- 2.获取key和value 格式:(value,key) -->
<li v-for="(value,key) in info">{{value}}-{{key}}</li>
<!-- 3.获取key和value和index 格式:(value,key,index) -->
<li v-for="(value,key,index) in info">{{value}}-{{key}}-{{index}}</li>
data: {
info: {
name: 'Joe',
age: 18,
height: 1.88
}
}
- v-for使用过程添加key
<li v-for="item in letters" :key="item">{{item}}</li>
data: {
letters: ['A', 'B', 'C', 'D', 'E']
}
1.6.1 多重循环遍历方法
data: {
books: [
{
id: 1,
name: '《算法导论》',
date: '2006-9',
price: 85.00,
count: 1
},
{
id: 2,
name: '《编程艺术》',
date: '2006-2',
price: 59.00,
count: 1
}
},
computed: {
totalPrice() {
// 1.普通的for循环
let totalPrice = 0
for (let i = 0; i < this.books.length; i++) {
totalPrice += this.books[i].price * this.books[i].count
}
return totalPrice
// 2.for (let i in this.books) ES6
let totalPrice = 0
for (let i in this.books) {
const book = this.books[i]
totalPrice += book.price * book.count
}
return totalPrice
// 3.for (let i of this.books)
let totalPrice = 0
for (let item of this.books) {
totalPrice += item.price * item.count
}
return totalPrice
// 4.reduce
return this.books.reduce(function (preValue, book) {
return preValue + book.price * book.count
}, 0)
}
}
1.7. v-model
v-model指令来实现表单元素和数据的双向绑定。
- 基本使用
<input type="text" v-model="message">
{{message}}
data: {
message: '你好'
}
- v-model结合radio类型
<label for="female">
<input type="radio" id="female" value="女" v-model="sex">女
</label>
<h2>您选择的性别是: {{sex}}</h2>
data: {
sex: '女'
}
- v-model结合checkbox类型
<!--1.checkbox单选框-->
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
</label>
<h2>您选择的是: {{isAgree}}</h2>
<button :disabled="!isAgree">下一步</button>
<!--2.checkbox多选框-->
<input type="checkbox" value="篮球" v-model="hobbies">篮球
<input type="checkbox" value="足球" v-model="hobbies">足球
<h2>您的爱好是: {{hobbies}}</h2>
<hr>
<label v-for="item in originHobbies" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}}
</label>
data: {
isAgree: false, // 单选框
hobbies: [], // 多选框,
originHobbies: ['篮球', '足球', '乒乓球', '羽毛球', '台球']
}
- v-model结合select类型
<!--1.选择一个-->
<select name="abc" v-model="fruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
</select>
<h2>您选择的水果是: {{fruit}}</h2>
<!--2.选择多个-->
<select name="abc" v-model="fruits" multiple>
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
</select>
<h2>您选择的水果是: {{fruits}}</h2>
data: {
fruit: '香蕉',
fruits: []
}
- v-model修饰符
<!--1.修饰符: lazy 失去焦点或敲回车键时才会更新-->
<input type="text" v-model.lazy="message">
<h2>{{message}}</h2>
<!--2.修饰符: number-->
<!-- 默认区情况下,在输入框中无论输入的是字母还是数字,都会默认被当做是字符串类型进行处理 -->
<!-- number修饰符可以让输入框中输入的内容自动转换成数字类型 -->
<input type="number" v-model.number="age">
<h2>{{age}}-{{typeof age}}</h2>
<!--3.修饰符: trim 过滤内容左右两边的空格-->
<input type="text" v-model.trim="name">
<h2>您输入的名字:{{name}}</h2>
data: {
age: 0,
name: ''
}
2.组件
2.1. 组件的基本使用
<div id="app">
<!--3.使用组件-->
<cpn></cpn>
<cpn></cpn>
</div>
// 1.创建组件构造器对象
const cpnC = Vue.extend({
template: `
<div>
<h2>我是标题</h2>
<p>我是内容,哈哈哈哈</p>
<p>我是内容,呵呵呵呵</p>
</div>`
})
// 2.注册组件 cpn是使用组件时的标签名,cpnC是创建组件构造器的名字
Vue.component('cpn' , cpnC)
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
2.2. 全局组件和局部组件
// 1.注册组件(全局组件, 意味着可以在多个Vue的实例下面使用)
Vue.component('cpn', cpnC)
// 2.局部组件,只能在这个 #app 实例中使用
const app = new Vue({
el: '#app',
components: {
cpn: cpnC // cpn使用组件时的标签名,cpnC是创建组件构造器的名字
}
})
2.3. 父组件和子组件
// 2.创建组件构造器(父组件)
const cpnC2 = Vue.extend({
template: `
<div>
<h2>我是标题2</h2>
<cpn1></cpn1>
</div>`,
components: {
cpn1: cpnC1 // 子组件
}
})
2.4. 组件的语法糖注册
// 1.注册组件与创建组件构造器合并在一起 全局注册
Vue.component('cpn1', {
template: `
<div>
<h2>我是标题1</h2>
</div>`
})
// 2.注册局部组件的语法糖
const app = new Vue({
el: '#app',
components: {
'cpn2': {
template: `
<div>
<h2>我是标题2</h2>
</div>`
}
}
})
2.5. 组件模板分离
<!--1.script标签, 注意:类型必须是text/x-template-->
<script type="text/x-template" id="cpn">
<div>
<h2>我是标题</h2>
</div>
</script>
<!--2.template标签--> // 推荐使用,简便
<template id="cpn">
<div>
<h2>我是标题</h2>
</div>
</template>
// 1.注册一个全局组件
Vue.component('cpn', {
template: '#cpn'
})
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
2.6. 组件中的数据存放
<template id="cpn">
<div>
<h2>{{title}}</h2>
<p>我是内容,呵呵呵</p>
</div>
</template>
// 1.注册一个全局组件
Vue.component('cpn', {
template: '#cpn',
data() {
return {
title: 'abc'
}
}
})
const app = new Vue({
el: '#app'
})
-
组件的data为什么是函数?
组件是可复用的
vue
实例,一个组件被创建好之后,就可能被用在各个地方,而组件不管被复用了多少次,组件中的data
数据都应该是相互隔离,互不影响的,基于这一理念,组件每复用一次,data
数据就应该被复制一次,之后,当某一处复用的地方组件内data
数据被改变时,其他复用地方组件的data
数据不受影响。
2.7. 组件通信-父组件向子组件传递数据
子组件通过 props 属性,绑定父组件数据,实现双方通信。
<div id="app">
<cpn :cmessage="message" :cmovies="movies"></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
// 父传子: props
const cpn = {
template: '#cpn',
// props: ['cmovies', 'cmessage'],
props: {
// 1.类型限制
// cmovies: Array,
// cmessage: String,
// 2.提供一些默认值, 以及必传值
cmessage: {
type: String,
default: 'aaaaaaaa',
required: true
},
// 类型是对象或者数组时, 默认值必须是一个函数
cmovies: {
type: Array,
default() {
return []
}
}
},
data() {
return {}
},
methods: {
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
cpn
}
})
2.8. 组件通信-子组件向父组件传递数据
父组件中自定义事件,子组件的监听事件通过$emit触发,发送数据到自定义事件中
<!--父组件模板-->
<div id="app">
<cpn @item-click="cpnClick"></cpn>
</div>
<!--子组件模板-->
<template id="cpn">
<div>
<button v-for="item in categories"
@click="btnClick(item)">
{{item.name}}
</button>
</div>
</template>
// 1.子组件
const cpn = {
template: '#cpn',
data() {
return {
categories: [
{id: 'aaa', name: '热门推荐'},
{id: 'bbb', name: '手机数码'},
{id: 'ccc', name: '家用家电'}
]
}
},
methods: {
btnClick(item) {
// 发射事件: 自定义事件
this.$emit('item-click', item)
}
}
}
// 2.父组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn // ES6 增强字面量
},
methods: {
cpnClick(item) {
console.log('cpnClick', item);
}
}
})
3.组件化高级(插槽 solt)
3.1. 插槽的基本使用
在子组件中,使用特殊的元素就可以为子组件开启一个插槽
中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容
<div id="app">
<cpn></cpn>
<cpn>
<h2>我是替换插槽的内容</h2>
<p>我也是替换插槽的内容</p>
</cpn>
<template id="cpn">
<div>
<slot>插槽中的默认内容</slot>
</div>
</template>
3.2.具名插槽slot
当子组件的功能复杂时,子组件的插槽可能并非是一个。这就需要给插槽起名字
使用具名插槽需要给 slot 加上name属性进行绑定,才能使用。
<div id="app">
<cpn><span slot="center">标题</span></cpn>
<cpn><button slot="left">返回</button></cpn>
</div>
<template id="cpn">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
3.3.插槽的作用域
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
4.Vue CLI
CLI(Command-Line Interface)
命令行界面,俗称脚手架
- Vue CLI是一个官方发布 vue.js项目脚手架
- 使用vue-cli可以快速搭建Vue开发环境以及对应的webpack配置
4.1.安装Vue CLI
- **前提:**安装 Vue CLI 前需要先安装 nodejs 和 webpack
4.1.1.安装Vue脚手架:
npm install -g @vue/cli
注意:上面安装的是Vue CLI的新版本,如果需要想按照Vue CLI2的方式初始化项目时不可以的。
4.1.2.如果需要使用 VueCLI 2.x 模板,需要全局安装一个桥接工具
npm install -g @vue/cli-init
4.2.Vue CLI 的使用
- Vue CLI2 初始化项目:
vue init webpack 项目名
- Vue CLI3 初始化项目:
vue create 项目名
- Vue CLI3 的配置在哪里?
- 启动配置服务器:vue ui
- node_modules/@vue/cli-service/lib/Service.js
- Runtime-Compiler和Runtime-only的区别
如果在之后的开发中,你依然使用template,就需要选择Runtime-Compiler;
如果你之后的开发中,使用的是.vue文件夹开发,那么可以选择Runtime-only。
Runtime-only 性能更好,占用更小
5. vue-router
5.1.安装 vue-router
npm install vue-router --save
5.2.使用vue-router
- 第一步: 创建路由组件
- 第二步: 配置路由映射: 组件和路径映射关系
- 第三步: 使用路由: 通过和
5.2.1.创建 router 实例
// 配置路由相关的信息
import VueRouter from 'vue-router'
import Vue from 'vue'
// 1.通过Vue.use(插件), 安装插件
Vue.use(VueRouter)
// 2.创建VueRouter对象
const routes = []
// 3.创建router实例
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes
})
// 4.将router对象传入到Vue实例
export default router
5.2.2.挂载到Vue实例中
import Vue from 'vue'
import App from './App'
import router from './router'
new Vue({
el: '#app',
router,
render: h => h(App)
})
- 步骤一:创建路由组件
<template>
<div>
<h2>我是首页</h2>
<p>我是首页内容, 哈哈哈</p>
</div>
</template>
<script>
export default {
name: "Home"
}
</script>
<style scoped>
</style>
- 步骤二:配置组件和路径的映射关系
// 配置路由相关的信息
import VueRouter from 'vue-router'
import Vue from 'vue'
// 导入
import Home from '../components/Home'
// 1.通过Vue.use(插件), 安装插件
Vue.use(VueRouter)
// 2.创建VueRouter对象
const routes = [
{
path: '',
// redirect重定向
redirect: '/home'
},
{
path: '/home',
component: Home
},
{
path: '/about',
component: About
}
]
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes,
mode: 'history',
linkActiveClass: 'active'
})
// 3.将router对象传入到Vue实例
export default router
- 步骤三:使用路由
- : 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个标签。
- : 该标签会根据当前的路径, 动态渲染出不同的组件。是显示当前路由的位置,它放在哪里,组件就在哪里渲染。
- 在路由切换时, 切换的是挂载的组件, 其他内容不会发生改变。
<template>
<div id="app">
<h2>我是APP组件</h2>
<router-link to="/home">首页</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style scope>
.active {
color: #f00;
}
</style>
5.2.3. 路由属性修改
5.2.3.1 路由的默认路径
在routes中配置一个映射,path 配置的根路径是 / ,redirect 是重定向
const routes = [
{
path: '',
// redirect重定向
redirect: '/home'
}
]
5.2.3.2 HTML5的History模式
改变页面 URL 的方式有两种:
- URL 的hash(哈希)
- HTML5的 History
- 默认情况下,路径的改变使用的 URL 的 hash
如果希望使用HTML5的history模式,进行如下配置即可:
const router = new VueRouter ({
routes,
mode: 'history'
})
5.2.3.3 router-link 补充
-
to : 用于指定跳转的路径
<router-link to='/home' tag='li'>首页</router-link>
-
tag : tag可以指定之后渲染成什么组件, 比如上面的代码会被渲染成一个
- 元素, 而不是
-
<router-link to="/home" tag="button">首页</router-link>
-
replace : replace不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中
<router-link to="/home" replace>首页</router-link>
-
active-class : 当对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称,但是通常不会修改类的属性, 会直接使用默认的router-link-active即可.用的少,一般不用。
<router-link to="/home" tag="button" active-class="active">首页</router-link>
-
路由代码跳转
<template> <div id="app"> <h2>我是APP组件</h2> <button @click="homeClick">首页</button> <button @click="aboutClick">关于</button> <router-view></router-view> </div> </template> <script> export default { name: 'App', methods: { homeClick() { // 通过代码的方式修改路由 vue-router // push => pushState // this.$router.push('/home') this.$router.replace('/home') console.log('homeClick'); }, aboutClick() { // this.$router.push('/about') this.$router.replace('/about') console.log('aboutClick'); } } } </script>
5.2.4 动态路由
在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:
/user/aaaa或/user/bbbb
除了有前面的/user之外,后面还跟上了用户的ID
这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)。
{
path: '/user/:id',
component: User,
}
<div>
<h2>{{$route.params.id}}</h2>
</div>
<router-link to="/user/123">用户</router-link>
5.2.5 懒加载
- 路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块.
- 只有在这个路由被访问到的时候, 才加载对应的组件
// import Home from '../components/Home' // 普通加载
const Home = () => import('../components/Home') // 懒加载
5.2.6 嵌套路由
比如在home页面中, 我们希望通过/home/news和/home/message访问一些内容.一个路径映射一个组件, 访问这两个路径也会分别渲染两个组件.
{
path: '/home',
component: Home,
meta: {
title: '首页'
},
children: [
{
path: 'news',
component: HomeNews
},
{
path: 'message',
component: HomeMessage
}
]
}
<template>
<div>
<h2>我是首页</h2>
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">消息</router-link>
<router-view></router-view>
</div>
</template>
5.2.7 传递参数
传递参数主要有两种类型: params和query
- params的类型:
配置路由格式: /router/:id
传递的方式: 在path后面跟上对应的值
传递后形成的路径: /router/123, /router/abc - query的类型:
配置路由格式: /router, 也就是普通配置
传递的方式: 对象中使用query的key作为传递方式
传递后形成的路径: /router?id=123, /router?id=abc
5.2.7.1 传递参数方式一:
<router-link
:to="{path: '/profile',
query: {name: 'why', age: 18, height: 1.88}
}">
</router-link>
5.2.7.2 传递参数二:JavaScript代码
export default {
name: 'App',
methods: {
toprofile() {
this.$router.push({
path: '/profile',
query: {
name: 'kobe',
age: 19,
height: 1.87
}
})
}
}
}
5.2.8 获取参数
获取参数通过 r o u t e 对 象 获 取 的 . 在 使 用 了 v u e − r o u t e r 的 应 用 中 , 路 由 对 象 会 被 注 入 每 个 组 件 中 , 赋 值 为 t h i s . route对象获取的. 在使用了 vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this. route对象获取的.在使用了vue−router的应用中,路由对象会被注入每个组件中,赋值为this.route ,并且当路由切换时,路由对象会被更新。
<template>
<div>
<h2>我是Profile组件</h2>
<h2>{{$route.query}}</h2>
<h2>{{$route.query.name}}</h2>
<h2>{{$route.query.age}}</h2>
<h2>{{$route.query.height}}</h2>
</div>
</template>
5.2.9 $route 和 $router 是有区别的
r o u t e 和 route和 route和router是有区别的
- r o u t e r 为 V u e R o u t e r 实 例 , 想 要 导 航 到 不 同 U R L , 则 使 用 router为VueRouter实例,想要导航到不同URL,则使用 router为VueRouter实例,想要导航到不同URL,则使用router.push方法
- $route为当前router跳转对象里面可以获取name、path、query、params等
5.2.10 导航守卫
-
vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.
-
vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发.
利用beforeEach来完成标题的修改
{
path: '/profile',
component: Profile,
meta: {
title: '档案'
},
}
// 前置守卫(guard)
router.beforeEach((to, from, next) => {
// 从from跳转到to
window.document.title = to.matched[0].meta.title
next()
})
如果是后置钩子, 也就是afterEach, 不需要主动调用next()函数.
5.2.11 keep-alive
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
-
include - 字符串或正则表达,只有匹配的组件会被缓存
-
exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存
<keep-alive exclude="Profile,User">
<router-view/>
</keep-alive>
- 前端渲染和后端渲染
- 第一步:导入路由对象,并且调用 Vue.use(VueRouter)
- 第二步:创建路由实例,并且传入路由映射配置
- 第三步:在Vue实例中挂载创建的路由实例
6. vuex
简单的将其看成把需要多个组件共享的变量全部存储在一个对象里面。
然后,将这个对象放在顶层的Vue实例中,让其他组件可以使用。
VueJS带给我们最大的便利是什么呢?没错,就是响应式。
6.1. 安装vuex
npm install vuex --save
6.2. 单界面的状态管理
- State:不用多说,就是我们的状态。(你姑且可以当做就是data中的属性)
- View:视图层,可以针对State的变化,显示不同的信息。(这个好理解吧?)
- Actions:这里的Actions主要是用户的各种操作:点击、输入等等,会导致状态的改变。
6.3. 案例
1. 首先,我们需要在某个地方存放我们的Vuex代码:
先创建一个文件夹store,并且在其中创建一个index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './mudules/moduleA'
// 1.安装插件
Vue.use(Vuex)
// 2.创建对象
const state = { // 唯一数据源
counter: 1000
}
const store = new Vuex.Store({
state: { // 唯一数据
counter: 0
},
mutations: {}, // 方法
actions: {}, // 异步操作
getters: {}, // store中的计算属性
modules: {} // 模块划分
})
// 3.导出store独享
export default store
2. 其次,我们让所有的Vue组件都可以使用这个store对象
来到main.js文件,导入store对象,并且放在new Vue中
这样,在其他Vue组件中,我们就可以通过this.$store的方式,获取到这个store对象了
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.config.productionTip = false
new Vue({
el: '#app',
store,
render: h => h(App)
})
3. 对使用步骤,做一个简单的小节:
-
提取出一个公共的store对象,用于保存在多个组件中共享的状态
-
将store对象放置在new Vue对象中,这样可以保证在所有的组件中都可以使用到
-
在其他组件中使用store对象中保存的状态即可
- 通过this.$store.state.属性的方式来访问状态
- 通过this.$store.commit(‘mutation中方法’)来修改状态
- 修改数据是通过dispatch调用actions里的方法
-
注意事项:
-
我们通过提交mutation的方式,而非直接改变store.state.count。
-
这是因为Vuex可以更明确的追踪状态的变化,所以不要直接改变store.state.count的值。
-
6.4. Vuex核心概念
1. State 唯一数据源
单一数据源
const state = { // 唯一数据源
counter: 1000,
students: [
{id: 111, name:'Joe', age:18},
{id: 112, name:'Kobe', age:24}
]
}
2. Getters 计算属性
需要从store中获取一些state编译后的状态
getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数.
getters: { // store中的计算属性
powerCounter(state){
return state.counter * state.counter
},
more20stu(state){
return state.students.filter(s => s.age >=20)
},
more20stuLength(state , getters){
return getters.more20stu.length
}
}
3. Mutation 方法 - 状态更新
Mutation主要包括两部分:
- 字符串的事件类型(type)
- 一个回调函数(handler),该回调函数的第一个参数就是state。
payload是一个对象.
mutations:{ // 方法
increment(state) {
state.counter++
}
incrementCount(state,count) {
state.counter += count
},
updateInfo(state) {
state.info.name = 'Joe'
}
}
methods: {
addition(){
this.$store.commit('increment')
},
addCount(count) { // commit('参数名',值) 提交给mutations
this.$store.commit('incrementCount', count)
},
updateInfo(){
this.$store.dispatch('aUpdateInfo')
}
asyncUpdateName(){ // 异步
this.$store.dispatch('aUpdateName')
}
}
4. Action 异步操作
Action类似于Mutation, 但是是用来代替Mutation进行异步操作的.
修改数据是通过dispatch调用actions里的方法
context是什么?
- context是和store对象具有相同方法和属性的对象.
- 也就是说, 我们可以通过context去进行commit相关的操作, 也可以获取context.state等.
actions: { // 专门处理异步操作
// context:上下文
// 在actions中不是state ,而是content
aUpdateInfo(context) {
setTimeout(() => {
context.commit('updateInfo')
// console.log(payload.message);
// payload.success()
}, 1000)
}
}
5. Module 模块
Vuex允许我们将store分割成模块(Module), 而每个模块拥有自己的state、mutations、actions、getters等
export default {
state: {
name: 'zhangsan'
},
mutations: {
updateName(state, payload) {
state.name = payload
}
},
getters: {
fullname(state) {
return state.name + '111'
}
},
actions: {
aUpdateName(context) {
// console.log(context);
setTimeout(() => {
context.commit('updateName', 'wangwu')
}, 1000)
}
}
}
7. axios
- 安装
npm i axios --save
7.1. axios 的基本使用
axios({
url:'http://123.207.32.32:8000/home/multidata',
method: 'get'
}).then(res => console.log(res))
axios({
url: 'http://123.207.32.32:8000/home/data',
params: {
type: 'pop',
page: 1
}
}).then(res => console.log(res))
7.2. axios 发送请求(并发请求)
// 2.axios发送请求(并发请求)
axios.all([axios({
url: 'http://123.207.32.32:8000/home/multidata'
// url: '/home/multidata'
}),axios({
url: 'http://123.207.32.32:8000/home/data',
params: {
type: 'sell',
page: 2
}
})]).then(results => {
console.log(results);
})
7.3. 提取全局配置
// 3.提取全局配置 (推荐使用实例提取配置,不推荐全局配置)
axios.defaults.baseURL = 'http://123.207.32.32:8000'
axios.defaults.timeout = 5000
7.4. 创建对应的 axios 的实例
// 4.创建对应的axios的实例
const instance1 = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
7.5. 封装axios
import axios from 'axios'
// 直接是axios ,就是全局的
// axios.create创建的就是局部的
export function request(config) {
// 1.创建axios实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
// 2.请求拦截 axios的拦截器
// 2.1.请求拦截的作用
instance.interceptors.request.use(config => {
// console.log(config);
// 1.config中的一些信息不符合服务器的要求
// 2.每次发送网络请求时,都希望在界面显示一个请求的图标
// 3.某些网络请求(比如登录(token)),必须携带一些特殊的信息
return config
}, err => {
// console.log(err);
})
// 2.2.响应拦截
instance.interceptors.response.use(res => {
console.log(res);
return res.data
}, err => {
console.log(err);
})
// 3.发送真正的网络请求
return instance(config)
}
7.6 使用封装的axios模块
import {request} from "./network/request"
request({
url: '/home/multidata'
}).then(res => {
// console.log(res);
}).catch(err => {
// console.log(err);
})
// request({
// url: '/home/multidata'
// },res => {
// console.log(res);
// },err => {
// console.log(err);
// })
vue响应式原理?
数据发生变化后,会重新对页面渲染,这就是Vue响应式
步骤:侦测数据变化,收集数据,更新视图