目录
前题
一、编程说明
二、vue3.0和vue2.0代码例子作比
三、扩展vue和react
四、vue3.0开发过渡笔记
版本
vue3的安装使用
生命周期的区别
整体区别
总结
首先了解一个新的功能首先要看它为什么出现,以及它的出现对现在的开发生态有哪些改变。
在vue2中我们进行开发叫做配置式开发 ,同一个功能逻辑可能需要 在data选项里写写,在methods里动动,生命周期再写两句,开发的时候可能不会觉得有什么。但是维护起来却有大问题。特别你要是对业务不熟悉接手别人的代码。
我一直都想着怎样能够面向功能块开发,将一个独立完整的业务功能封装成独立的代码块,这样既方便维护。同时封装相同的逻辑进行封装引用 ,也极大的降低了工作量,减少复制黏贴,以及复制黏贴过程中产生的错误。
vue3.0的变化可以总结为以下几点:
Vue3打包
打包使用可视化面板打包就可以但是打包后的dist文件不可以直接启动
如果你想在本地运行的话需要使用phpstudy配置一下才可以打开
然后要记住vue3打包后接口没有数据的情况那可能是网卡了等一会就好了
vue2.0采用面向对象编程的思想,vue3.0则采用函数式编程的思想。
详细介绍:
面向对象编程
什么是对象
1、对象是单个事物的抽象,是一个具体的事物(一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个与远程服务器的连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程)。
2、对象是一个容器,封装了属性(property;属性是对象的状态特征)和方法(method;方法是对象的行为。例:完成了)。
3、在实际开发中,对象是一个抽象的概念,可以将其简单理解为:数据集或功能集。
4、ECMAScript-262 把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数。
5、严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。
面向对象的特征
编程思想:
面向对象:提出需求,找对象,对象解决,注重的是结果
原型prototype
构造函数、实例、原型三者之间的关系
函数式编程
1、vue3 英文版说明
vue3 API相关的RFC,地址:https://github.com/vuejs/rfcs/blob/function-apis/active-rfcs/0000-function-api.md
2、函数式编程是一种编程范式,主要是利用函数把运算过程封装起来,通过组合各种函数来计算结果。
例子,假设我们要把字符串 functional programming is great 变成每个单词首字母大写,我们可以这样实现:
var string = 'functional programming is great';
var result = string
.split(' ')
.map(v => v.slice(0, 1).toUpperCase() + v.slice(1))
.join(' ');
上面的例子先用 split 把字符串转换数组,然后再通过 map 把各元素的首字母转换成大写,最后通过 join 把数组转换成字符串。 整个过程就是 join(map(split(str))),体现了函数式编程的核心思想: 通过函数对数据进行转换。
由此我们可以得到,函数式编程有两个基本特点:
• 通过函数来对数据进行转换
• 通过串联多个函数来求结果
3、对比声明式与命令式(见二中e3.0例子容易理解)
//命令式
var CEOs = [];
//----------for(var i = 0; i < companies.length; i++){
for(var i in companies){
CEOs.push(companies[i].CEO)
}
//声明式
var CEOs = companies.map(c => c.CEO);
4、函数式编程常见特性
无副作用,指调用函数时不会修改外部状态,即一个函数调用 n 次后依然返回同样的结果。
var a = 1;
// 含有副作用,它修改了外部变量 a
// 多次调用结果不一样
function test1() {
a++
return a;
}
// 无副作用,没有修改外部状态
// 多次调用结果一样
function test2(a) {
return a + 1;
}
透明引用
指一个函数只会用到传递给它的变量以及自己内部创建的变量,不会使用到其他变量。
var a = 1;
var b = 2;
// 函数内部使用的变量并不属于它的作用域
function test1() {
return a + b;
}
// 函数内部使用的变量是显式传递进去的
function test2(a, b) {
return a + b;
}
不可变变量
指的是一个变量一旦创建后,就不能再进行修改,任何修改都会生成一个新的变量。使用不可变变量最大的好处是线程安全。多个线程可以同时访问同一个不可变变量,让并行变得更容易实现。 由于 JavaScript 原生不支持不可变变量,需要通过第三方库来实现。 (如 Immutable.js,Mori 等等)
var obj = Immutable({ a: 1 });
var obj2 = obj.set('a', 2);
console.log(obj); // Immutable({ a: 1 })
console.log(obj2); // Immutable({ a: 2 })
函数是一等公民
我们常说函数是JavaScript的"第一等公民",指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。下文将要介绍的闭包、高阶函数、函数柯里化和函数组合都是围绕这一特性的应用
5、常见的函数式编程模型
1.闭包(Closure)
2.高阶函数
map
map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。map 不会改变原数组。
假设我们有一个包含名称和种类属性的对象数组,我们想要这个数组中所有名称属性放在一个新数组中
// 使用高阶函数
var animals = [
{ name: "Fluffykins", species: "rabbit" },
{ name: "Caro", species: "dog" },
{ name: "Hamilton", species: "dog" },
{ name: "Harold", species: "fish" },
{ name: "Ursula", species: "cat" },
{ name: "Jimmy", species: "fish" }
];
var names = animals.map(x=>x.name);
console.log(names); //["Fluffykins", "Caro", "Hamilton", "Harold", "Ursula", "Jimmy"]
filter
filter() 方法会创建一个新数组,其中包含所有通过回调函数测试的元素。filter 为数组中的每个元素调用一次 callback 函数, callback 函数返回 true 表示该元素通过测试,保留该元素,false 则不保留。filter 不会改变原数组,它返回过滤后的新数组。
假设我们有一个包含名称和种类属性的对象数组。 我们想要创建一个只包含狗(species: “dog”)的数组。
// 使用高阶函数
var animals = [
{ name: "Fluffykins", species: "rabbit" },
{ name: "Caro", species: "dog" },
{ name: "Hamilton", species: "dog" },
{ name: "Harold", species: "fish" },
{ name: "Ursula", species: "cat" },
{ name: "Jimmy", species: "fish" }
];
var dogs = animals.filter(x => x.species === "dog");
console.log(dogs); // {name: "Caro", species: "dog"}
// { name: "Hamilton", species: "dog" }
reduce
reduce 方法对调用数组的每个元素执行回调函数,最后生成一个单一的值并返回。 reduce 方法接受两个参数:1)reducer 函数(回调),2)一个可选的 initialValue。
假设我们要对一个数组的求和:
// 不使用高阶函数
const arr = [5, 7, 1, 8, 4];
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum = sum + arr[i];
}
console.log(sum);//25
// 使用高阶函数
const arr = [5, 7, 1, 8, 4];
const sum = arr.reduce((accumulator, currentValue) => accumulator + currentValue,0);
console.log(sum)//25
函数组合 (Composition)
函数式编程的一个特点是通过串联函数来求值。然而,随着串联函数数量的增多,代码的可读性就会不断下降。函数组合来解决这个问题。
假设有一个 compose 函数,它可以接受多个函数作为参数,然后返回一个新的函数。当我们为这个新函数传递参数时,该参数就会「流」过其中的函数,最后返回结果。
//两个函数的组合
var compose = function(f, g) {
return function(x) {
return f(g(x));
};
};
//或者
var compose = (f, g) => (x => f(g(x)));
var add1 = x => x + 1;
var mul5 = x => x * 5;
compose(mul5, add1)(2);// =>15
vue3 -- DEMO
count is {{ count }}
plusOne is {{ plusOne }}
转换为vue2 -- DEMO
count is {{ count }}
plusOne is {{ plusOne }}
1、
对比一下,我们不难发现:
vue2是将mounted,data,computed,watch之类的方法作为一个对象的属性进行导出。
vue3新增了一个名为setup的入口函数,value, computed, watch, onMounted等方法都需要从外部import。
函数式编程为组件的编写提供了更高的灵活度与可读性,并且更符合一个前端编写者的习惯(或者叫做“编程直觉”)。
2、
在vue2中,watch、computed、data、method等API都是直接作为对象的属性,传给vue实例的。这意味着,我们开发者在开发时,脑中需要给这个对象的不同属性(data、method、mounted之类的)建立联系。但一旦代码规模变大,这种联系就非常吃力了,这集中表现在大型vue组件代码的可读性很低。我想,每个维护过1000+行vue组件的开发者都会有所体会
而在vue3中,我们可以像写一个方法一样去写这个组件的JS逻辑部分,使用import来按需引入。这样的好处显而易见,首先就是我们需要写的代码量少了,其次就是我们可以封装更多的子函数、引用更多的公共函数去维护我们的代码,第三就是代码的可读性变高了。(当然,我们的打包体积也会变小)---- 此处需要调研
调研笔记1:
调研笔记2: async函数、await
关键字
async
关键字声明的函数。 async函数是AsyncFunction构造函数的实例, 并且其中允许使用await
关键字。async
和await
关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise
。//name 函数名称。
//param 要传递给函数的参数的名称。
async function name([param[, param[, ... param]]]) {
statements //包含函数主体的表达式。可以使用await机制。
}
async
/await
的目的为了简化使用基于promise的API时所需的语法。async
/await
的行为就好像搭配使用了生成器和promise。async
/ await
关键字就可以在异步代码中使用普通的try
/ catch
代码块。await
关键字只在async函数内有效。 async function foo() {
return 1
}
等价于:
function foo() {
return Promise.resolve(1)
}
调研文章
vue中使用async和await来实现同步和异步_aaron9185的博客-CSDN博客_async await vue
调研笔记3: Promise
Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
一个Promise,这个promise要么会通过一个由async函数返回的值被解决,要么会通过一个从async函数中抛出的(或其中没有被捕获到的)异常被拒绝。
vue和react最大的区别有两个,一是双向数据绑定 VS 单向数据流,二是模板语法 VS JSX。
vue3.0在函数式编程方面,使其在一些API的使用、组件JS层的逻辑上更像react,但其仍为模板语法。
查看版本: npm view vue versions
npm i vue@lasted:下载的是vue2
vue3
npm i vue@next
区别一:vue3中推崇使用函数式编程;各种创建实例,都调用函数来创建,我们从vue中解构出各种各样的函数来使用
区别二:Performance [pəˈfɔːməns]
重写了虚拟DOM的实现(跳过静态节点,只处理动态节点)
update性能提高1.3~2倍
SSR速度提高了2~3倍
区别三:Tree shaking [ˈʃeɪkɪŋ]
可以将无用模块“剪辑”,仅打包需要的【webpack新版本的】
区别四 Fragment ['frægmənt]
不再限于模板中的单个根节点[文档碎片]
区别五
可以把组件内部的部分内容挂载到除#app的容器中(
你好,世界
区别六
可在嵌套层级中等待嵌套的异步依赖项,嵌套一个异步组件,可以在获取到数据之前加载loading效果
父组件------------------
loading.....
子组件--------------------------
{{ msg }}
区别七:TypeScript更好的TypeScript支持
区别八:vue3支持把组件中的某些内容以图形的方式绘制到canvas画布上(Custom Renderer API自定义渲染器API)Apache ECharts
自定义渲染器API
用户可以尝试WebGL自定义渲染器
区别九:vue3使用的Composition API:(Composition API聚合API):vue2遵循options API,vue3遵循Composition API
options API:数据根据功能划分到data、methods、computed、watch区域(分散式API)
Composition API:vue3中所有的数据方法都放到了setup()方法中,全部组合到了一起,没有细分(聚合式API)
组合式API,替换原有的 Options [ˈɒpʃnz] API
根据逻辑相关性组织代码,提高可读性和可维护性
更好的重用逻辑代码(避免mixins混入时命名冲突的问题)
但是依然可以延用 Options [ˈɒpʃnz] API
区别十:vue3中的响应式数据
劫持,基于Proxy实现的;vue3中的响应式数据劫持,不再基于vue2的Object.defineProperty(),而是基于ES6内置的Proxy(不兼容IE)。
//vue3中的响应式
//基于ES6中的Proxy来实现的,new Proxy返回obj的代理对象
let proxObj = new Proxy(obj, {//对obj的第一层做劫持
//target代理的对象,key值
get(target, key) {
return target[key]
},
set(target, key, value) {
if (target[key === value]) return;
target[key] = value;
//控制视图重新渲染,操作代理对象时触发渲染
console.log('rendering');
}
})
区别十一:获取页面数据组件
import { ref, onMounted } from 'vue';
import api from '@/config/api/jsonConfig.js'
import commonData from '@/config/general/commonData.js'
/*
Fcn:请求表格数据接口名
autoRequest:是否需要挂载完成后自动加载数据
*/
export default (Fcn,autoRequest) => {
// 表格绑定数据
const tableData = ref([])
// 表格页码数据
const paginationOpt = ref({
pageNumber: 1,
pageSize: 20,
totalRecords: 0
})
// 获取表格数据
const getTableData = async (params) => {
let d = await api[Fcn]({ params: { ...params, organizationUID: commonData.currentOrg.organizationUID } })
if (!d) return
tableData.value =d.data.pagination? d.data.records:d.data
paginationOpt.value = d.data.pagination
}
// 翻页
const handleSizeChange = (v) => {
paginationOpt.value.pageSize = v
getTableData(paginationOpt.value)
}
const handleCurrentChange = (v) => {
paginationOpt.value.pageNumber = v
getTableData(paginationOpt.value)
}
// 挂载完成请求数据
onMounted(() => {
if(autoRequest) getTableData()
})
return { tableData, paginationOpt, getTableData, handleSizeChange, handleCurrentChange }
}
页面组件:只需要将方法名传入即可
export default defineComponent({
setup() {
return {
...useTable("examSourcegetList",true),
};
},
});
1.function component 将会是接下来各大框架发展的一个方向,function天然对TS的友好也是一个重要的影响。
2.react hook的上手成本相对于vue会难一些,vue天生规避了一些react中比较难处理的地方。
3.hook一定是大前端的一个趋势。
4.目前的项目中前端中体现的函数式编程比较多,后端更多的还是OOP的思想。
5.在大型的偏向工程话的项目中,使用面向对象的方式方便拓展,更易编写。在项目中的比较小的一些组织模块可以使用函数式编程来提高效率。
参考文章:vue3 为什么要使用composition函数式编程_白马湖小龙王的博客-CSDN博客_vue3函数式编程
从函数式编程和面向对象的思考到Vue3的函数式编程_治愈云_q1942951600的博客-CSDN博客_vue3函数式编程