一、前言
本系列文章旨在,复习渐进式JavaScript框架:Vue全家桶。夯实移动大前端技术基本功。为后期搭建超级App的Hybrid框架、小程序开发、Web站点开发做知识储备
文章列表:
- 01-?Vue全家桶核心知识|Vue基础【Vue概述、Vue基本使用、Vue模板语法、基础案例、Vue常用特性、综合案例】
- 02-?Vue全家桶核心知识|Vue常用特性【表单操作、自定义指令、计算属性、侦听器、过滤器、生命周期、综合案例】
- 03-?Vue全家桶核心知识|组件化开发【组件化开发思想、组件注册、Vue调试工具用法、组件间数据交互、组件插槽、基于组件的
- 04-?Vue全家桶核心知识|多线程与网络【前后端交互模式、promise用法、fetch、axios、综合案例】
- 05-?Vue全家桶核心知识|Vue Router【基本使用、嵌套路由、动态路由匹配、命名路由、编程式导航、基于vue-router的案例】
- 06-?Vue全家桶核心知识|前端工程化【模块化相关规范、webpack、Vue 单文件组件、Vue 脚手架、Element-UI 的基本使用】
- 07-?Vue全家桶核心知识|Vuex【Vuex的基本使用、Vuex中的核心特性、vuex案例】
二、Vuex概述
1. 组件之间共享数据的方式
- 父向子传值:
v-bind
属性绑定 - 子向父传值:
v-on
事件绑定 - 兄弟组件之间共享数据:
EventBus
$on
接收数据的那个组件$emit
发送数据的那个组件
2. Vuex 是什么
- Vuex 是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。
3. 使用 Vuex 统一管理状态的好处
使用Vuex管理数据的好处:
- A.能够在vuex中集中管理共享的数据,便于开发和后期进行维护
- B.能够高效的实现组件之间的数据共享,提高开发效率
- C.存储在vuex中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新
4. 什么样的数据适合存储到 Vuex 中
一般情况下,只有组件之间共享的数据,才有必要存储到 vuex 中;对于组件中的私有数据,依旧存储在组件 自身的 data 中即可
二、Vuex的基本使用
1.命令行方式
- 安装 vuex 依赖包:
npm install vuex --save
- 导入 vuex 包:
import Vuex from 'vuex' Vue.use(Vuex)
- 创建 store 对象
const store = new Vuex.Store({ // state 中存放的就是全局共享的数据 state: { count: 0 } })
- 将 store 对象挂载到 vue 实例中
new Vue({ el: '#app', render: h => h(app), router, // 将创建的共享数据对象,挂载到 Vue 实例中 // 所有的组件,就可以直接从 store 中获取全局的数据了 store })
2.可视化页面操作
创建带有vuex的vue项目,打开终端,输入命令:vue ui
当项目仪表盘打开之后,我们点击页面左上角的项目管理下拉列表,再点击Vue项目管理器
点击创建项目,如下图所示
第一步,设置项目名称和包管理器
第二步,设置手动配置项目
第三步,设置功能项
第四步,创建项目
3.使用Vuex完成计数器案例
打开刚刚创建的vuex项目,找到src目录中的App.vue组件,将代码重新编写如下:
<template>
<div>
<my-addition></my-addition>
<p>----------------------------------------</p>
<my-subtraction></my-subtraction>
</div>
</template>
<script>
import Addition from './components/Addition.vue'
import Subtraction from './components/Subtraction.vue'
export default {
data() {
return {}
},
components: {
'my-subtraction': Subtraction,
'my-addition': Addition
}
}
</script>
<style>
</style>
在components文件夹中创建Addition.vue组件,代码如下:
<template>
<div>
<h3>当前最新的count值为:</h3>
<button>+1</button>
</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style>
</style>
在components文件夹中创建Subtraction.vue组件,代码如下:
<template>
<div>
<h3>当前最新的count值为:</h3>
<button>-1</button>
</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style>
</style>
最后在项目根目录(与src平级)中创建 .prettierrc 文件,编写代码如下:
{
"semi":false,
"singleQuote":true
}
三、Vuex中的核心特性
1. 核心概念概述
- State
- Mutation
- Action
- Getter
2. State
State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储
- 例如,打开项目中的store.js文件,在State对象中可以添加我们要共享的数据,如:count:0
在组件中访问State的方式:
- 1.)
this.$store.state.全局数据名称
如:this.$store.state.count
- 2.)先按需导入mapState函数: import { mapState } from ‘vuex’
- 然后数据映射为计算属性: computed:{ …mapState([‘全局数据名称’]) }
3. Mutation
Mutation 用于变更 Store中 的数据。
- ① 只能通过 mutation 变更 Store 数据,不可以直接操作 Store 中的数据
- ② 通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化
- 可以在触发 mutations 时传递参数:
使用mutations的第一种方式:
this.$store.commit()
是触发mutations
的第一种方式
使用方式:
打开store.js文件,在mutations中添加代码如下
mutations: {
add(state,step){
//第一个形参永远都是state也就是$state对象
//第二个形参是调用add时传递的参数
state.count+=step;
}
}
然后在Addition.vue中给按钮添加事件代码如下:
<button @click="Add">+1</button>
methods:{
Add(){
//使用commit函数调用mutations中的对应函数,
//第一个参数就是我们要调用的mutations中的函数名
//第二个参数就是传递给add函数的参数
this.$store.commit('add',10)
}
}
使用mutations的第二种方式:
通过刚才导入的 mapMutations 函数,将需要的 mutations 函数,映射为当前组件的 methods 方法:
import { mapMutations } from 'vuex'
methods:{
...mapMutations(\['add'])
}
如下:
import { mapState,mapMutations } from 'vuex'
export default {
data() {
return {}
},
methods:{
//获得mapMutations映射的sub函数
...mapMutations(['sub']),
//当点击按钮时触发Sub函数
Sub(){
//调用sub函数完成对数据的操作
this.sub(10);
}
},
computed:{
...mapState(['count'])
}
}
3. Action
在mutations中不能编写异步的代码,会导致vue调试器的显示出错。
- 在vuex中我们可以使用Action来执行异步操作。
- Mutation 的方式间接变更数据。
- 触发 actions 异步任务时携带参数:
触发 actions 的第一种方式
this.$store.dispatch()
是触发 actions 的第一种方式,
操作步骤如下:
打开store.js文件,修改Action,如下:
actions: {
addAsync(context,step){
setTimeout(()=>{
context.commit('add',step);
},2000)
}
}
然后在 Addition.vue
中给按钮添加事件代码如下:
<button @click="AddAsync">...+1</button>
methods:{
AddAsync(){
this.$store.dispatch('addAsync',5)
}
}
触发 actions 的第二种方式:
- 第二种方式:
import { mapActions } from 'vuex' methods:{ ...mapMutations(\['subAsync']) }
- 通过刚才导入的 mapActions 函数,将需要的 actions 函数,映射为当前组件的 methods 方法:
如下:
import { mapState,mapMutations,mapActions } from 'vuex'
export default {
data() {
return {}
},
methods:{
//获得mapMutations映射的sub函数
...mapMutations(['sub']),
//当点击按钮时触发Sub函数
Sub(){
//调用sub函数完成对数据的操作
this.sub(10);
},
//获得mapActions映射的addAsync函数
...mapActions(['subAsync']),
asyncSub(){
this.subAsync(5);
}
},
computed:{
...mapState(['count'])
}
}
4. Getter
Getter用于对Store中的数据进行加工处理形成新的数据
- ① Getter 可以对 Store 中已有的数据加工处理之后形成新的数据,类似 Vue 的计算属性
- 它只会包装Store中保存的数据,并不会修改Store中保存的数据
- ② Store 中数据发生变化,Getter 的数据也会跟着变化。
打开store.js文件,添加getters,如下:
export default new Vuex.Store({
.......
getters:{
//添加了一个showNum的属性
showNum : state =>{
return '最新的count值为:'+state.count;
}
}
})
然后打开Addition.vue中,添加插值表达式使用getters
<h3>{{$store.getters.showNum}}</h3>
或者也可以在Addition.vue中,导入mapGetters,并将之映射为计算属性
import { mapGetters } from 'vuex'
computed:{
...mapGetters(\['showNum'])
}
使用 getters 的第一种方式:“`
使用 getters 的第二种方式:
四、vuex案例
To do List
完成具体功能
- ① 动态加载任务列表数据
- ② 实现文本框与store数据的双向同步
- ③ 完成添加任务事项的操作
- ④ 完成删除任务事项的操作
- ⑤ 动态绑定复选框的选中状态
- ⑥ 修改任务事项的完成状态
- ⑦ 统计未完成的任务的条数
- ⑧ 清除已完成的任务事项
- ⑨ 实现任务列表数据的动态切换
1. 初始化案例
首先使用vue ui初始化一个使用vuex的案例
然后打开public文件夹,创建一个list.json文件,文件代码如下:
[
{
"id": 0,
"info": "Racing car sprays burning fuel into crowd.",
"done": false
},
{
"id": 1,
"info": "Japanese princess to wed commoner.",
"done": false
},
{
"id": 2,
"info": "Australian walks 100km after outback crash.",
"done": false
},
{
"id": 3,
"info": "Man charged over missing wedding girl.",
"done": false
},
{
"id": 4,
"info": "Los Angeles battles huge wildfires.",
"done": false
}
]
再接着,打开main.js,添加store.js的引入,如下:
import Vue from 'vue'
import App from './App.vue'
import store from './store.js'
// 1. 导入 ant-design-vue 组件库
import Antd from 'ant-design-vue'
// 2. 导入组件库的样式表
import 'ant-design-vue/dist/antd.css'
Vue.config.productionTip = false
// 3. 安装组件库
Vue.use(Antd)
new Vue({
store,
render: h => h(App)
}).$mount('#app')
再接着打开store.js,添加axios请求json文件获取数据的代码,如下:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
//所有任务列表
list: [],
//文本输入框中的值
inputValue: 'AAA'
},
mutations: {
initList(state, list) {
state.list = list
},
setInputValue(state,value){
state.inputValue = value
}
},
actions: {
getList(context) {
axios.get('/list.json').then(({ data }) => {
console.log(data);
context.commit('initList', data)
})
}
}
})
最后,代开App.vue文件,将store中的数据获取并展示:
<template>
<div id="app">
<a-input placeholder="请输入任务" class="my_ipt" :value="inputValue" @change="handleInputChange" />
<a-button type="primary">添加事项</a-button>
<a-list bordered :dataSource="list" class="dt_list">
<a-list-item slot="renderItem" slot-scope="item">
<!-- 复选框 -->
<a-checkbox :checked="item.done">{{item.info}}</a-checkbox>
<!-- 删除链接 -->
<a slot="actions">删除</a>
</a-list-item>
<!-- footer区域 -->
<div slot="footer" class="footer">
<!-- 未完成的任务个数 -->
<span>0条剩余</span>
<!-- 操作按钮 -->
<a-button-group>
<a-button type="primary">全部</a-button>
<a-button>未完成</a-button>
<a-button>已完成</a-button>
</a-button-group>
<!-- 把已经完成的任务清空 -->
<a>清除已完成</a>
</div>
</a-list>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'app',
data() {
return {
// list:[]
}
},
created(){
// console.log(this.$store);
this.$store.dispatch('getList')
},
methods:{
handleInputChange(e){
// console.log(e.target.value)
this.$store.commit('setInputValue',e.target.value)
}
},
computed:{
...mapState(['list','inputValue'])
}
}
</script>
<style scoped>
#app {
padding: 10px;
}
.my_ipt {
width: 500px;
margin-right: 10px;
}
.dt_list {
width: 500px;
margin-top: 10px;
}
.footer {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
2. 完成添加事项
首先,打开App.vue文件,给“添加事项”按钮绑定点击事件,编写处理函数
//绑定事件
<a-button type="primary" @click="addItemToList">添加事项</a-button>
//编写事件处理函数
methods:{
......
addItemToList(){
//向列表中新增事项
if(this.inputValue.trim().length <= 0){
return this.$message.warning('文本框内容不能为空')
}
this.$store.commit('addItem')
}
}
然后打开store.js编写addItem
export default new Vuex.Store({
state: {
//所有任务列表
list: [],
//文本输入框中的值
inputValue: 'AAA',
//下一个id
nextId:5
},
mutations: {
........
//添加列表项
addItem(state){
const obj = {
id :state.nextId,
info: state.inputValue.trim(),
done:false
}
//将创建好的事项添加到数组list中
state.list.push(obj)
//将nextId值自增
state.nextId++
state.inputValue = ''
}
}
......
})
3. 完成删除事项
首先,打开App.vue文件,给“删除”按钮绑定点击事件,编写处理函数
//绑定事件
<a slot="actions" @click="removeItemById(item.id)">删除</a>
//编写事件处理函数
methods:{
......
removeItemById(id){
//根据id删除事项
this.$store.commit('removeItem',id)
}
}
然后打开store.js编写addItem
export default new Vuex.Store({
......
mutations: {
........
removeItem(state,id){
//根据id删除事项数据
const index = state.list.findIndex( x => x.id === id )
// console.log(index);
if(index != -1) state.list.splice(index,1);
}
}
......
})
4. 完成选中状态的改变
首先,打开App.vue文件,给“复选”按钮绑定点击事件,编写处理函数
//绑定事件
<a-checkbox :checked="item.done" @change="cbStateChanged(item.id,$event)">{{item.info}}</a-checkbox>
//编写事件处理函数
methods:{
......
cbStateChanged(id,e){
//复选框状态改变时触发
const param = {
id:id,
status:e.target.checked
}
//根据id更改事项状态
this.$store.commit('changeStatus',param)
}
}
然后打开store.js编写addItem
export default new Vuex.Store({
......
mutations: {
........
changeStatus(state,param){
//根据id改变对应事项的状态
const index = state.list.findIndex( x => x.id === param.id )
if(index != -1) state.list[index].done = param.status
}
}
......
})
5. 剩余项统计
打开store.js,添加getters完成剩余项统计
getters:{
unDoneLength(state){
const temp = state.list.filter( x => x.done === false )
console.log(temp)
return temp.length
}
}
打开App.vue,使用getters展示剩余项
//使用映射好的计算属性展示剩余项
<!-- 未完成的任务个数 -->
<span>{{unDoneLength}}条剩余</span>
//导入getters
import { mapState,mapGetters } from 'vuex'
//映射
computed:{
...mapState(['list','inputValue']),
...mapGetters(['unDoneLength'])
}
6. 清除完成事项
首先,打开App.vue文件,给“清除已完成”按钮绑定点击事件,编写处理函数
<!-- 把已经完成的任务清空 -->
<a @click="clean">清除已完成</a>
//编写事件处理函数
methods:{
......
clean(){
//清除已经完成的事项
this.$store.commit('cleanDone')
}
}
然后打开store.js编写addItem
export default new Vuex.Store({
......
mutations: {
........
cleanDone(state){
state.list = state.list.filter( x => x.done === false )
}
}
......
})
7. 点击选项卡切换事项
打开App.vue,给“全部”,“未完成”,“已完成”三个选项卡绑定点击事件,编写处理函数
并将列表数据来源更改为一个getters。
<a-list bordered :dataSource="infoList" class="dt_list">
......
<!-- 操作按钮 -->
<a-button-group>
<a-button :type="viewKey ==='all'?'primary':'default'" @click="changeList('all')">全部</a-button>
<a-button :type="viewKey ==='undone'?'primary':'default'" @click="changeList('undone')">未完成</a-button>
<a-button :type="viewKey ==='done'?'primary':'default'" @click="changeList('done')">已完成</a-button>
</a-button-group>
......
</a-list>
//编写事件处理函数以及映射计算属性
methods:{
......
changeList( key ){
//点击“全部”,“已完成”,“未完成”时触发
this.$store.commit('changeKey',key)
}
},
computed:{
...mapState(['list','inputValue','viewKey']),
...mapGetters(['unDoneLength','infoList'])
}
打开store.js,添加getters,mutations,state
export default new Vuex.Store({
state: {
......
//保存默认的选项卡值
viewKey:'all'
},
mutations: {
......
changeKey(state,key){
//当用户点击“全部”,“已完成”,“未完成”选项卡时触发
state.viewKey = key
}
},
......
getters:{
.......
infoList(state){
if(state.viewKey === 'all'){
return state.list
}
if(state.viewKey === 'undone'){
return state.list.filter( x => x.done === false )
}
if(state.viewKey === 'done'){
return state.list.filter( x => x.done === true )
}
}
}
})
专题系列文章
1. 前知识
- 01-探究iOS底层原理|综述
- 02-探究iOS底层原理|编译器LLVM项目【Clang、SwiftC、优化器、LLVM】
- 03-探究iOS底层原理|LLDB
- 04-探究iOS底层原理|ARM64汇编
2. 基于OC语言探索iOS底层原理
- 05-探究iOS底层原理|OC的本质
- 06-探究iOS底层原理|OC对象的本质
- 07-探究iOS底层原理|几种OC对象【实例对象、类对象、元类】、对象的isa指针、superclass、对象的方法调用、Class的底层本质
- 08-探究iOS底层原理|Category底层结构、App启动时Class与Category装载过程、load 和 initialize 执行、关联对象
- 09-探究iOS底层原理|KVO
- 10-探究iOS底层原理|KVC
- 11-探究iOS底层原理|探索Block的本质|【Block的数据类型(本质)与内存布局、变量捕获、Block的种类、内存管理、Block的修饰符、循环引用】
- 12-探究iOS底层原理|Runtime1【isa详解、class的结构、方法缓存cache_t】
- 13-探究iOS底层原理|Runtime2【消息处理(发送、转发)&&动态方法解析、super的本质】
- 14-探究iOS底层原理|Runtime3【Runtime的相关应用】
- 15-探究iOS底层原理|RunLoop【两种RunloopMode、RunLoopMode中的Source0、Source1、Timer、Observer】
- 16-探究iOS底层原理|RunLoop的应用
- 17-探究iOS底层原理|多线程技术的底层原理【GCD源码分析1:主队列、串行队列&&并行队列、全局并发队列】
- 18-探究iOS底层原理|多线程技术【GCD源码分析1:dispatch_get_global_queue与dispatch_(a)sync、单例、线程死锁】
- 19-探究iOS底层原理|多线程技术【GCD源码分析2:栅栏函数dispatch_barrier_(a)sync、信号量dispatch_semaphore】
- 20-探究iOS底层原理|多线程技术【GCD源码分析3:线程调度组dispatch_group、事件源dispatch Source】
- 21-探究iOS底层原理|多线程技术【线程锁:自旋锁、互斥锁、递归锁】
- 22-探究iOS底层原理|多线程技术【原子锁atomic、gcd Timer、NSTimer、CADisplayLink】
- 23-探究iOS底层原理|内存管理【Mach-O文件、Tagged Pointer、对象的内存管理、copy、引用计数、weak指针、autorelease
3. 基于Swift语言探索iOS底层原理
关于函数
、枚举
、可选项
、结构体
、类
、闭包
、属性
、方法
、swift多态原理
、String
、Array
、Dictionary
、引用计数
、MetaData
等Swift基本语法和相关的底层原理文章有如下几篇:
- 01-?Swift5常用核心语法|了解Swift【Swift简介、Swift的版本、Swift编译原理】
- 02-?Swift5常用核心语法|基础语法【Playground、常量与变量、常见数据类型、字面量、元组、流程控制、函数、枚举、可选项、guard语句、区间】
- 03-?Swift5常用核心语法|面向对象【闭包、结构体、类、枚举】
- 04-?Swift5常用核心语法|面向对象【属性、inout、类型属性、单例模式、方法、下标、继承、初始化】
- 05-?Swift5常用核心语法|高级语法【可选链、协议、错误处理、泛型、String与Array、高级运算符、扩展、访问控制、内存管理、字面量、模式匹配】
- 06-?Swift5常用核心语法|编程范式与Swift源码【从OC到Swift、函数式编程、面向协议编程、响应式编程、Swift源码分析】
4. C++核心语法
- 01-C++核心语法|C++概述【C++简介、C++起源、可移植性和标准、为什么C++会成功、从一个简单的程序开始认识C++】
- 02-?C++核心语法|C++对C的扩展【::作用域运算符、名字控制、struct类型加强、C/C++中的const、引用(reference)、函数】
- 03-?C++核心语法|面向对象1【 C++编程规范、类和对象、面向对象程序设计案例、对象的构造和析构、C++面向对象模型初探】
- 04-?C++核心语法|面向对象2【友元、内部类与局部类、强化训练(数组类封装)、运算符重载、仿函数、模板、类型转换、 C++标准、错误&&异常、智能指针】
- 05-?C++核心语法|面向对象3【 继承和派生、多态、静态成员、const成员、引用类型成员、VS的内存窗口】
5. Vue全家桶
- 01-?Vue全家桶核心知识|Vue基础【Vue概述、Vue基本使用、Vue模板语法、基础案例、Vue常用特性、综合案例】
- 02-?Vue全家桶核心知识|Vue常用特性【表单操作、自定义指令、计算属性、侦听器、过滤器、生命周期、综合案例】
- 03-?Vue全家桶核心知识|组件化开发【组件化开发思想、组件注册、Vue调试工具用法、组件间数据交互、组件插槽、基于组件的
- 04-?Vue全家桶核心知识|多线程与网络【前后端交互模式、promise用法、fetch、axios、综合案例】
- 05-?Vue全家桶核心知识|Vue Router【基本使用、嵌套路由、动态路由匹配、命名路由、编程式导航、基于vue-router的案例】
- 06-?Vue全家桶核心知识|前端工程化【模块化相关规范、webpack、Vue 单文件组件、Vue 脚手架、Element-UI 的基本使用】
- 07-?Vue全家桶核心知识|Vuex【Vuex的基本使用、Vuex中的核心特性、vuex案例】
其它底层原理专题
1. 底层原理相关专题
2. iOS相关专题
- 01-iOS底层原理|iOS的各个渲染框架以及iOS图层渲染原理
- 02-iOS底层原理|iOS动画渲染原理
- 03-iOS底层原理|iOS OffScreen Rendering 离屏渲染原理
- 04-iOS底层原理|因CPU、GPU资源消耗导致卡顿的原因和解决方案