一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
在vue3.x中,v-if的优先级大于v-for,这意味着 v-if
将没有权限访问 v-for
里的变量。这将抛出一个错误,因为 v-if
指令将首先被使用,而迭代的变量 user
此时不存在。
object是引用类型,如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了其他也改变了。
js中只有函数构成作用域(只有函数的{}构成作用域,对象的{}以及if(){}都不构成作用域),data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会互相影响。
1、computed是计算属性,也就是依赖某个值或者props通过计算得来得数据;
2、computed的值是在getter执行之后进行缓存的,只有在它依赖的数据发生变化,会重新调用getter来计算;
3、 不支持异步,当computed内有异步操作时无效,无法监听数据的变化;
1、watch是监听器,可以监听某一个数据,然后执行相应的操作;
2、不支持缓存,数据变直接会触发相应的操作;
3、监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
4、支持异步操作;
什么时候用computed 什么时候用watch 比较合适?当多个属性影响一个属性的时候,建议用computed,比如:当一个值发生变化之后,会引起一系列的操作,这种情况就适合用watch;
Hash模式
属于Vue路由的默认模式。
访问的路径中包含#号,#后面就是对应页面的路由名称。
支持页面刷新。
获取当前页面路由某个参数值,使用js中split()进行截取获取。
History模式
另一种vue路由模式,路径中没有#号,访问路径看起来像api请求一样。
需要将前端对应路由,配置到后端数据库,否则直接配置history模式,页面无法刷新(404)
获取当前页面路由某个参数值,使用this.$route.query.参数(通过键-获取值)~获取当前路径某个参数值;
普通函数可以有匿名函数,也可以有具体名函数,但是箭头函数都是匿名函数。
箭头函数不能用于构造函数,不能使用new
在普通函数中,this总是指向调用它的对象,如果用作构造函数,this指向创建的对象实例。
箭头函数不创建this也可以说箭头函数本身没有this,但是它在声明时可以捕获其所在上下文的this供自己使用
箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
ES5 中作用域有:全局作用域、函数作用域。没有块作用域的概念。
ES6 中新增了块级作用域。块作用域由 { } 包括,if语句和 for语句里面的{ }也属于块作用域。
1.由于 JavaScript 的限制,Vue 不能检测数组和对象的变化;尤雨溪 - 性能代价和获得用户体验不成正比。
2.在vue中写在data中的属性是是可以转换成getter和setter,换一句话就是响应式的,其他定义在data之外的数据,是无法响应的渲染,意思就是改变数据页面也不会刷新,所以一切要渲染到页面上的数据,必须写在data中。
3.你的数据确实修改了,但是网页上不刷新,可以使用this.$forceUpdate()方法 (强制刷新)
4.vue不允许在已经创建的实例上动态添加新的根级响应式属性,不过可以使用Vue.set()方法将响应式的属性添加到嵌套的对象上。
Vue.set(object, key, value)
export default() {
data() {
food: {
name: 'apple'
}
}
}
Vue.set(food, 'count', 1);
var vm = new Vue({
data:{
items:['a','b','c']
}
})
vm.item[1] = 'x' //不是响应性的
//解决办法
Vue.set(vm.items,indexOfItem,newValue)
//vm.$set
vm.$set(vm.items,indexOfItem,newValue)
//Array.prototype.splice
vm,items.splice(indexOfItem,1,newValue)
5.数组的API,中能够改变原始数组的都能触发更新;
1.ref被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的$refs对象上。
2.如果在普通的DOM元素上使用,引用指向的就是DOM元素;如果用在子组件上,引用就指向组件。
3.this.$refs.mobile 类似于JQ中的$("#id"),获取对应的DOM元素
4.通俗的讲,ref特性就是为元素或子组件赋予一个ID引用,通过this.$refs.refName来访问元素或子组件的实例
5.$el:是用于获取组件内DOM(包括子组件,当前.vue组件,以及父组件),组件不属于DOM,所以使用$el获取组件内的DOM。
子组件changeMsg()
{{msg}}
父组件this.$refs.children.changeMsg() // 调用children子组件实例中的changeMsg方法,children为自定义名称
this.$parent方法,实际中$parent用的非常少——考虑到耦合度的原因。
1.父组件
2.子组件this.$parent 可以访问到父组件上所有的 data(){ 里的数据信息和生命周期方法,methods里的方法 }
1.Vue 是通过 webpack 实现的模块化,因此可以使用 import 来引入模块,例如:
2.此外,你还可以在 bulid/webpack.base.conf.js 文件中修改相关配置:
意思是,你的模块可以省略 ".js",".vue",“.json” 后缀,webpack 会在之后自动添加上;可以用 "@" 符号代替 "src" 字符串等。
3.export 用来导出模块,Vue 的单文件组件通常需要导出一个对象,这个对象是 Vue 实例的选项对象,以便于在其它地方可以使用 import 引入。而 new Vue() 相当于一个构造函数,在入口文件 main.js 构造根组件的同时,如果根组件还包含其它子组件,那么 Vue 会通过引入的选项对象构造其对应的 Vue 实例,最终形成一棵组件树。
4.export 和export default 的区别在于:export 可以导出多个命名模块,例如:
//demo1.js export const str = 'hello world' export function f(a){ return a+1 }
对应的引入方式:
//demo2.js import { str, f } from 'demo1'
export default 只能导出一个默认模块,这个模块可以匿名,例如:
//demo1.js export default { a: 'hello', b: 'world' }
对应的引入方式:
//demo2.js import obj from 'demo1'
引入的时候可以给这个模块取任意名字,例如 "obj",且不需要用大括号括起来。
5.在这种不使用{}来引用模块的情况下,input模块时的命名是随意的,即如下三种命名都是正确的。因为它总是会解释到A.js中默认的export default。
import A from './A'
import MyA from '.A'
import Someting from '.A'
下面使用了花括号的命名方式 {A}来导入A.js,生效的前提是只有在模块A.js中有如下命名导出的为A的export name的代码
//B.js
import {A} from './A' //正确因为A.js 中有命名为A
import {myA} from './A' //正确因为A.js 中有命名为myA
//A.js
export const A = 42
export const myA = 43
一级目录
build: webpack 配置相关的目录
config: webpack 配置相关的目录
node_modules: npm install 安装的依赖代码库
src:我们存放的源码,我们开发的所哟代码都放在src目录下。
staic: 存放一些第三方静态资源的目录
test:测试目录,没有太大用处,可以删除
一级文件:
.babelrc: babel的一些配置,(将es6编译成es5的一些配置)
.editorconfig:编辑器的一些配置(包括编码格式,缩进风格,换行格式)
.eslintignore:配置我们不会对build文件和config文件进行语法检查。
.eslintrc.js: eslint的配置文件,主要是定义一些代码编写风格的规则。
.gitignore:配置git仓库忽略的一些文件(不会上传)
index.html: 入口html 文件。
package.json:项目的一些配置信息(项目的一些具体信息)
src 文件夹下的 目录:
assets 文件夹: 存放静态资源,例如:图片,font字体等。
conponents 文件夹: 存放组件,里面你可以在建文件来分组件,比如建 header 问价夹, footer 文件夹
router 文件夹: 配置路由文件
App.vue 文件: App.vue是我们的主组件,所有页面都是在App.vue下进行切换的
main.js 文件: 主要作用是初始化vue实例并使用需要的插件
父组件中:
子组件中:
子组件中:
父组件中:
2.选择新建全局代码片段文件,创建一个名为vue.json的文件。
3.在vue.json文件复制如下代码。
{
"Print to console": {
"prefix": "vue",
"body": [
"",
"",
"",
"",
"",
"",
"",
],
"description": "Log output to console"
}
}
4.新建vue页面后,输入快捷键: vue , 回车就可以创建vue模版了。
mounted(){
console.log(this.isok) //可以获取isok值
setInterval(function(){
console.log(this.isok) //不可以获取isok值
},3000);
}
不可以获取isok值是因为定时器的this指向window的
mounted(){
var that = this; //这时的this指向vue实例
setInterval(function(){
console.log(that.isok) //可以获取isok值
},3000);
}
1.表的数据源中的每个记录都应该有一个唯一的'key'属性,或者将表的'rowKey'设置为唯一的主键
如果后端给了唯一ID值可以直接绑定
2. 后端没有唯一的id,可以用索引代替
localStorage.setItem只能存储字符串,所以在储存的时候如果是对象先转换为字符串。
1.保存数据语法:
localStorage.setItem("key", "value");
2.读取数据语法:
var lastname = localStorage.getItem("key");
3.删除数据语法:
localStorage.removeItem("key");
一、状态管理(vuex)简介
vuex是专为vue.js应用程序开发的状态管理模式。它采用集中存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。vuex也集成刀vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能。
二、状态管理核心
状态管理有5个核心,分别是state、getter、mutation、action以及module。分别简单的介绍一下它们:
1、state
state为单一状态树,在state中需要定义我们所需要管理的数组、对象、字符串等等,只有在这里定义了,在vue.js的组件中才能获取你定义的这个对象的状态。
2、getter
getter有点类似vue.js的计算属性,当我们需要从store的state中派生出一些状态,那么我们就需要使用getter,getter会接收state作为第一个参数,而且getter的返回值会根据它的依赖被缓存起来,只有getter中的依赖值(state中的某个需要派生状态的值)发生改变的时候才会被重新计算。
3、mutation
更改store中state状态的唯一方法就是提交mutation,就很类似事件。每个mutation都有一个字符串类型的事件类型和一个回调函数,我们需要改变state的值就要在回调函数中改变。我们要执行这个回调函数,那么我们需要执行一个相应的调用方法:store.commit。
4、action
action可以提交mutation,在action中可以执行store.commit,而且action中可以有任何的异步操作。在页面中如果我们要嗲用这个action,则需要执行store.dispatch
5、module
module其实只是解决了当state中很复杂臃肿的时候,module可以将store分割成模块,每个模块中拥有自己的state、mutation、action和getter。
export default{
computed:{
//1.state共享中的数据
//this.$store.state.count;//第一种方式调用state中的状态值
...mapState(['count']),
//4.getters 对store中的数据加工成新的数据,类型于Vue的计算属性
//this.$store.getters.showNum //第一种方式调用getters中的函数
...mapGetters(['showNum']),
},
methods:{
//2.mutations唯一可以改变state中数据方法
//this.$store.commit(['add']);//第一种方式调用muattions中的函数
...mapMutations(['sub']),
//3.actions异步操作
//this.$store.dispatch(['addcount']);//第一种方式调用actions中的函数
...mapActions(['addcount','addN']),
}
}
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state:{
count:9
},
mutations:{
add(state){
state.count++
},
sub(state,n){
state.count-=n;
},
addN(state,n){
state.count+=n;
},
addy(state){
state.count --;
}
},
actions:{
addcount(context){
setTimeout(() =>{
context.commit('add')
},5000)
},
addN(context){
setTimeout(()=>{
context.commit('addy')
},1000)
}
},
getters:{
showNum(state){
return '当前最新的数据是['+state.count+']'
}
}
})
/生命周期通俗说就是Vue实例从创建到销毁的过程,就是生命周期。
1.beforecreate (初始化界面前)
2.created (初始化界面后)
3.beforemount (渲染界面前)
4.mounted (渲染界面后)
5.beforeUpdate (更新数据前)
6.updated (更新数据后)
7.beforedestory (卸载组件前)
8.destroyed (卸载组件后)
Document
{{count}}
1.拆解字符串与数组
var array = [1,2,3,4];
console.log(...array);//1 2 3 4
var str = "String";
console.log(...str);//S t r i n g
2. 求最大值
var array = [1,2,3,4,3];
var max2 = Math.max(...array);
console.log(max2);//4
3.push方法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1.push(...arr2);
//arr1 [0, 1, 2, 3, 4, 5]
4. 数组合并
ar arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
// ES6的合并数组
[...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ]
5. 拷贝数组或对象
//拷贝数组
var array0 = [1,2,3];
var array1 = [...array0];
console.log(array1);//[1, 2, 3]
//拷贝数组
var obj = {
age:1,
name:"lis",
arr:{
a1:[1,2]
}
}
var obj2 = {...obj};
console.log(obj2);//{age: 1, name: "lis", arr: {…}}
1.由于 Vue.js 是一个 视图层框架 并且作者(尤雨溪)严格准守 SoC (关注度分离原则),所以 Vue.js 并不包含 AJAX 的通信功能,为了解决通信问题,作者单独开发了一个名为 vue-resource 的插件,不过在进入 2.0 版本以后停止了对该插件的维护并推荐了 Axios 框架。少用jQuery,因为它操作Dom太频繁!
//安装axios命令
$ npm install axios
2. 发送git请求
// 为给定 ID 的 user 创建请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 可选地,上面的请求可以这样做
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
3.执行 post 请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
4.可以通过向 axios
传递相关配置来创建请求
// 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
5.一般在项目中的plugins文件中创建名为axios.js的文件,内容如下请求或响应被 then
或 catch
处理前拦截它们。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
一、Vue在谷歌浏览上测试插件
1.网盘地址:https://pan.baidu.com/s/14PoaihUHQZEJtiHNWUmdjg
2.谷歌浏览器中扩展程序,开启开发者模式,将下载的文件拖到窗口中即可。
3.然后重启浏览器就可以看见
二、中文简体汉化包插件
1.Chinese (Simplified) (简体中文)Language Pack for Visual Studio Code
2.这个插件一键把整个VSCode的文字转换成中文。一个全中文化的IDE是我们特别需要的。而且这个是官方汉化包,理解无障碍。
三、标签页插件
1.Bookmarks
2.它是代码中导航,在重要位置之间轻松快速地移动。不再需要搜索代码。它还支持一组选择命令,允许我们选择书签行和书签行之间的区域。
3.文件/首选项/快捷键设置,设置Bookmarks改为其它快捷键即可这里我改为了数字1做为标签。
四、补齐插件
1.Auto Close Tag
2.自动补全html标签,如输入将自动补全
五、浏览器自动刷新插件
1.Live Server
2.用于工作目录及其子目录。它也监视文件的变化,当这种情况发生时,它通过web套接字连接向浏览器发送消息,指示它重新加载。
六、代码高亮显示插件
1.Vetur
2.Vetur可以将“.vue”文件中的语法进行高亮显示,Vetur不仅支持Vue中的template模板以外,还支持大多数主流的前端开发脚本和插件,比如Sass、TypeScript、Jade和Less等等。
七、VScode中浏览器打开html文件
1.openChrome
2.安装后在html中鼠标右击,显示Open with Live Server
七、鼠标点击代码可以查看当前行代码,由谁向git版本上提交的代码。
Git History DIff
两种方式 params与query,特别注意:命名路由这种方式传递的参数,如果在目标页面刷新是会出错的。this.$router.push({ name: 'news', params: { userId: 666 }})
1.命名路由
就是在注册路由的地方需要给路由命名
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import Router from 'vue-router'
import App from '@/App'
Vue.config.productionTip = false
//注册路由
Vue.use(Router)
//实例化路由
export default new Router({
mode:'history',
routes:[
// {path:'/',component:App},
{path:'/news',
name:'news',
component:() => import('@/components/news'),
}
]
})
2.父组件通过点击事件 this.$router.push({ name: 'news', params: { userId: 123 }});给子组件设置路由名称及参数
{{ msg }}
3.子组件news.vue通过this.$route.params.userId,获取到父组件通过路由传过来的值。
this is the news page.the transform param is {{this.$route.params.userId}}
4.
查询参数其实就是在路由地址后面带上参数和传统的url参数一致的,传递参数使用query而且必须配合path来传递参数而不能用name,目标页面接收传递的参数使用query。
注意:和name配对的是params,和path配对的是query
this.$router.push({ path: '/news', query: { userId: 123 }});
1.命名路由就是在注册路由的地方需要给路由命名
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import Router from 'vue-router'
import App from '@/App'
Vue.config.productionTip = false
//注册路由
Vue.use(Router)
//实例化路由
export default new Router({
mode:'history',
routes:[
// {path:'/',component:App},
{path:'/news1',
name:'news1',
component:() => import('@/components/news1'),
}
]
})
2.父组件通过点击事件 this.$router.push({ path: '/news', query: { userId: 123 }});
{{ msg }}
3.子组件news1.vue通过this.$route.query.userId,获取到父组件通过路由传过来的值。
this is the news page.the transform param is {{this.$route.query.userId}}
4.
vue-router路由跳转方式
1.声明式(标签跳转)
2. 编程式( js跳转)
this.$router.push('/home')
this.$router.push({name:'home'})
this.$router.push({path:'/home'})
3.命名路由类似表单提交而查询就是url传递
4.1.命名路由搭配params,刷新页面参数会丢失
2.查询参数搭配query,刷新页面数据不会丢失
3.接受参数使用this.$router后面就是搭配路由的名称就能获取到值
4.name配对的是params,和path配对的是query
两则的区别:
使用params的路由, 可以在页面使用this.$route.params.xxx 获取参数,相当于post方法,携带的参数不会明文出现在url上。但是刷新路由后,该参数会消失。 不适于需要刷新页面,又可以取数的。
使用query的路由,可以在页面使用this.$route.query.xxx 获取参数,相当于get方法。携带的参数能在url上直接看到。即使刷新页面,参数也会一直保留。
除了可以使用 query传参解决页面刷新导致数据丢失的问题,
也可以考虑使用 localStorage,sessionStorage来保存参数,也可以使用vuex的store来保存。
5.this.$router.resolve方法,当遇到需要在点击事件或函数中实现,新窗口打开新页面
methods:{
goDetail(scope,myCode){
if(myCode == "3"){
var stationId = '3'+scope.row.stationId
}
let routeUrl = this.$router.resolve({
path:'/business/stationCenter/index',
query:{
projectName:scope.row.projectName,
stationName:scope.row.stationName,
}
})
window.open(routeUrl.href,'_black')
}
}
6.this.$router 和 this. $route 区别
this.$router(路由实例) : 是VueRouter的实例.包含了很多属性和对象(比如 history 对象),任何页面都可以调用其 push(), replace(), go() 等方法。
this.$route: 表示当前路由对象,每一个路由都会有一个 route 对象,是一个局部的对象,可以获取对应的 name, path, meta, params, query 等属性。
7.点击
8.this.$router.go(n),该方法采用一个整数作为参数,表示历史堆栈中前进或后退多少步。
//向前移动一条记录
this.router.go(1)
//返回一条记录
this.router.go(-1)
1.定义无参全局过滤器
{{ msg | msgFormat}}
2.定义有参数的全局过滤器
{{ msg | msgFormat('疯狂','--')}}
3.定义局部过滤器
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
msg: '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的男人'
},
methods: {},
//定义私用局部过滤器。只能在当前 vue 对象中使用
filters: {
dataFormat(msg) {
return msg+'xxxxx';
}
}
});
4.当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤优先于全局过滤器被调用.
5. 一个表达式可以使用多个过滤器。过滤器之间需要用管道符"|"隔开。其执行顺序从左往右
6.表单元素外可以直接使用filter方法,表单元素应用filter方法会报错。全局用filter,局部用filters。
1.vue当中的插槽,指的即是slot,是组件当中的一块HTML模板。该模板是否显示,以及如何显示由其父组件说了算。不过插槽显示的位置是由子组件决定 ,你将slot写在组件template的哪块,父组件传过来的模板将来就显示在哪块!
2.单个插槽是vue官方的叫法。你也可以叫它默认插槽。另外因为该插槽不用设置name属性,也可以称其为匿名插槽。
父组件
我是一个父组件
有位非常漂亮的女同事,有天起晚了没有时间化妆便急忙冲到公司。结果那天她被记旷工了……
子组件
我是子组件
3.父组件在
我是一个父组件
我是子组件
有位非常漂亮的女同事,有天起晚了没有时间化妆便急忙冲到公司。结果那天她被记旷工了……
4.具名插槽匿名插槽是没有名字的插槽。如果给插槽加上name属性,我们可以将其称为具名插槽!
父组件
我是一个父组件
老张
老王
老李
子组件
我是子组件
最终渲染的结果:
我是一个父组件
我是子组件
老张
老王
老李
5.作用域插槽:slot-scope = "scope" 来获取作用域插槽 :data绑定的数据。scope.$index 就是该行的下标,scope.row就是该行的数据所有消息对象,有了这两个参数我们就可以实现编辑(分配,转派,完工),删除等功能。
{{
scope.row.status == "0"
? "待办"
: scope.row.status == "1"
? "处置中"
: "完成"
}}
对于vue-cli 3.x版本前端配置服务器代理在vue.config.js中设置服务器代理;如下图:
devServer:{
port:8089, //端口号
host:'0.0.0.0',
https:false,
open:true, //配置自动启动浏览器
proxy:{
'/metadata':{
target:'http://172.18.16.157:7086',
ws:true,
changeOrigin:true,
pathRewrite:{
'^/metadata':'/'
}
},
}
}
target对应的属性值为你准备向后端服务器发送请求的主机+端口,含义为:相当于把前端发送请求的主机+端口自动替换成挂载的主机和端口,这样前后端的主机端口都一一就不会存在跨域问题;
ws:表示WebSocket协议;
changeOrigin:true;表示是否改变原域名;这个一定要选择为true;
这样发送请求的时候就不会出现跨域问题了。
1.Promise构造函数的参数是一个函数,函数里面的代码是异步的,即Promise里面的操作,Promise中的函数的第一个参数是回调函数,resolve用来触发then里面的代码,第二个参数是回调函数,reject用来触发catch中的代码
在一个promise链中,只要任何一个promise被reject,promise链就被破坏了,reject之后的promise都不会再执行,而是直接调用.catch方法。
2.async关键字实际是通过Promise实现,如果async 函数中有返回一个值 ,当调用该函数时,内部会转化成一个promise 对象作为返回
await表示“等待”,修饰返回promise 对象的表达式。注意await 关键字只能放到async 函数里面。
3.Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。
注意: Promise.all成功结果数组里的数据顺序和Promise.all接收到的数组顺序是一致的。 所以在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
4.Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。
5.Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
let P1 = new Promise((resolve, reject) => {
resolve('成功')
})
let P2 = new Promise((resolve, reject) => {
resolve('success')
})
let P3 = Promse.reject('失败')
Promise.all([P1, P2]).then((result) => {
console.log(result) //控制台打印结果['成功了', 'success']
}).catch((error) => {
console.log(error)
})
Promise.all([P1,P3,P2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 控制台打印结果 '失败'
})
Promise.all([
findNoteFilesByPid(params), // 请求的接口1
getTags(params1) // 请求的接口2
]).then((res) => { //返回的res是一个数组 [{code: 200,data: null, msg: ''},{code: 200,data: null, msg: ''}]
if (res[0].code === 200) { //res[0] 是接口1的返回数据
if (res[1].code === 200) { //res[1] 是接口2的返回数据
}
}
})
6.resolve当放在函数里面的时候只有调用的时候才会被执行,console.log("并不会打印出-要返回的数据可以任何数据例如接口返回数据 ")
开始异步请求
const promiseClick =()=>{
console.log('点击方法被调用')
let p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成Promise');
resolve('要返回的数据可以任何数据例如接口返回数据');
}, 2000);
});
return p
}
我们包装好的函数最后,会return出Promise对象,也就是说,执行这个函数我们得到了一个Promise对象。接下来就可以用Promise对象上有then、catch方法了,这就是Promise的强大之处
promiseClick().then(function(data){
console.log(data);
//后面可以用传过来的数据做些其他操作
//data=要返回的数据可以任何数据例如接口返回数据
});
Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用。这样能够按顺序,每隔两秒输出每个异步回调中的内容。在runAsync2中传给resolve的数据,能在接下来的then方法中拿到。
promiseClick()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return runAsync3();
})
.then(function(data){
console.log(data);
});
1.简单的说,在vue中我们使用模板HTML语法组建页面的,使用render函数我们可以用js语言来构建DOM
因为vue是虚拟DOM,所以在拿到template模板时也要转译成VNode的函数,而用render函数构建DOM,vue就免去了转译的过程。
当使用render函数描述虚拟DOM时,vue提供一个函数,这个函数是就构建虚拟DOM所需要的工具。官网上给他起了个名字叫createElement。还有约定的简写叫h
2.虚拟DOM与真实DOM的区别
虚拟DOM不会进行排版与重绘操作 ,虚拟DOM就是把真实DOM转换为Javascript代码,并且真实DOM频繁操作排版、重绘效率相比虚拟DOM 效率会低很多,比如原生操作真实DOM浏览器会从构建DOM树开始从头到尾执行一遍流程。而虚拟DOM是用Object来代表一颗节点,这个Object叫做VNode,然后使用两个VNode进行对比,根据对比后的结果修改真实DOM。
3.render函数:render函数接收一个 createElement 方法作为第一个参数用来创建VNode(虚拟DMO)
createElement(参数1, 参数2, 参数3) 中有三个参数
参数1:必须,规定将要渲染的HTML标签是什么。类型可以是字符串、对象或函数。比如”div”就是创建一个
render: function (createElement) {
//do something
return creatElement(参数1, 参数2, 参数3)
}
参数2中可用参数之类的
{
'class': {
// 和`v-bind:class`一样的API
},
style: {
// 和`v-bind:style`一样的API
},
attrs: {
// 正常的 html 特性
},
props: {
// 组件 props
},
domProps: {
// DOM 属性
},
on: {
// 事件监听器基于on
// 不再支持如 `v-on:keyup.enter` 修饰器,需手动匹配 keyCode
},
nativeOn: {
// 仅对于组件,用于监听原生组件,而不是组件内部使用`vm.$emit`触发的事件
},
directives: [
{
// 自定义指令,注意事项:不能对绑定的旧值设值
// vue 会为您持续追踪
}
],
scopedSlots: {
},
slot: '', // 如果组件是其他组件的子组件,需为 slot 指定名称
// 其他特殊顶层属性
key: '',
ref: ''
}
使用案例
export default{
components: {
'my-slot':slot,
'anchoredHeading': {
render: function (createElement) {
var self = this
return createElement('button', {
class: 'isTest',
// 和`v-bind:style`一样的 API
style: {
color: 'red',
fontSize: '14px'
},
// DOM 内容填充button中的文字
domProps: {
innerHTML: 'baz'
},
on: {
click: () => { alert('1') }
}
},'点击我')
}
}
},
}
渲染结果
1.let声明变量和const声明常量,两个都有块级作用域
ES5中是没有块级作用域的,并且var有变量提升,在let中,使用的变量一定要进行声明
2.箭头函数
ES6中的函数定义不再使用关键字function(),而是利用了()=>来进行定义
3.promise
Promise构造函数的参数是一个函数,函数里面的代码是异步的,即Promise里面的操作
4.import、export导入导出
ES6标准中,Js原生支持模块(module)。将JS代码分割成不同功能的小块进行模块化,将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导入的方式可以在其他地方使用
5.模板字符串
模板字符串是增强版的字符串,用反引号(`)标识,可以当作普通字符串使用,也可以用来定义多行字符串
6.... 展开运算符
可以将数组或对象里面的值展开;还可以将多个值收集为一个变量
7.for of循环
1.for...of获取的是对象的键值,for … in 获取的是对象的键名。
2. const { name } of persons
循环迭代 persons
对象数组,并且就地将 person
对象进行了解构。
const persons = [
{ name: 'John Smith' },
{ name: 'Jane Doe' }
];
for (const { name } of persons) {
console.log(name);
}
// 'John Smith'
// 'Jane Doe'
filter() 方法创建一个新的数组并返回,在新数组中的元素是通过检查指定数组中也就是调用filter方法的数组中符合条件的所有元素。
调用方法:
array.filter(function(currentValue, currentIndex, originalArray), thisValue)
参数说明:
currentValue 必填。当前元素的值
currentIndex可选。当前元素的索引值
originalArray可选。当前元素所属于的数组对象,也就是调用此方法的数组
返回数组对象中存在某属性的对象
var newarr = [
{ num: 1, val: 'test', flag: 'aa' },
{ num: 2, val: 'exam', flag: 'bb' }
]
console.log(newarr.filter(item => item.num===2 ))
// 输出 {num: 2, val: "ceshi2", flag: "aa2"}
去除字符串中的空串,null,false,undefined
var arr2 = ['1','',undefined, null, false, '2',]
console.log(arr2.filter(item => item))
// 输出 ["1", "2"]
去除数组中不符合要求项
var arr3 = [20, 30, 40, 50, 60]
console.log(arr3.filter(item => item>35))
// 输出 [40, 50, 60]
去除数组中重复项
var arr4 = [1, 2, 2, 3, 4, 4, 5, 6, 6]
console.log(arr4.filter((value, index, array)=>array.indexOf(value)===index))
// 输出 [1, 2, 3, 4, 5, 6]
1.Vue.extend返回的是一个扩展实例构造器,也就是预设了部分选项的Vue实例构造器。
1.其主要用来服务于Vue.component,用来生成组件
可以简单的理解为当在模板中遇到该组件名称作为标签的自定义元素时,会自动调用扩展实例构造器来生产组件实例,并挂载到自定义元素上。
Vue.extend扩展实例构造器
1. router.beforeEach((to,from,next)=>{})
2. 回调函数中的参数,to:进入到哪个路由去,from:从哪个路由离开,next:函数,决定是否展示你要看到的路由页面。
3. 如下例:main.js中设置全局前置守卫
router.beforeEach((to,from,next)=>{
if(to.path == '/login' || to.path == '/register'){
next();
}else{
alert('您还没有登录,请先登录');
next('/login');
}
})
全局后置钩子router.afterEach((to,from)=>{})
全局后置钩子router.afterEach((to,from)=>{})
只有两个参数,to:进入到哪个路由去,from:从哪个路由离。
如下,每次切换路由时,都会弹出alert,点击确定后,展示当前页面。
beforeRouteEnter:(to,from,next)=>{ alert("hello" + this.name);}
进行访问admin页面,会发现alert输出hello undefined
。这是因为,现在访问不到我们的data属性,执行顺序是不一致,这与的声明周期有关。在执行完之前,data数据还未渲染。所以这里,next()会给一个对应的回调,帮助完成。
离开这个组件时,beforeRouteLeave:(to,from,next)=>{}
beforeRouteLeave:(to,from,next)=>{
if(confirm("确定离开此页面吗?") == true){
next();
}else{
next(false);
}
}
beforeEnter:(to,from,next)=>{},用法与全局守卫一致。只是,将其写进其中一个路由对象中,只在这个路由下起作用。
1.localStorage(长期存储):和前者一样,区别在于浏览器关闭后数据依然存在。
2.sessionStorage(临时存储):为没一个数据维持一个存储区域,浏览器打开会创建,关闭浏览器就会消失。
创建一个登陆页面
登录
登陆后的页面
欢迎您:
{{name}}!
注销
您还未登录!
如果再localStorage中存储的是一个对象,那么在取值时可能会发生我这种情况。
let user = {
username : "张三",
password : "123456"
}
localStorage.setItem("user",user);
console.log(localStorage.getItem("user"))
输出为[object,Object]
发现无法正确读取对象中内容,目前发现最好的方法时先将对象转换成JSON,再保存就可以正常输出了,注意读取的时候再转换为对象。
let user = {
username : "张三",
password : "123456"
}
localStorage.setItem("user",JSON.stringify(user));
console.log(JSON.parse(localStorage.getItem("user")))
1. lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件_之后_进行同步。
意思是什么呢,就是说当我们在input输入框输入数据时,v-model绑定的值不会发发生变化,但是当我们停止输入,输入框失去焦点或者按下回车时,v-model绑定的值才会发生变化,即在“change”时而非“input”时更新:
2. number
自动将用户的输入值转为数值类型
。
这个修饰符通常很有用,因为即使在type="number"时,HTML输入的元素的值也总会返回字符串。如果这个值无法被parseFloat()解析,则会返回原始的值。虽然输入的是数字,但它的类型其实是string。
3. trim
自动过滤用户输入的首尾空白字符
。
1.reduce()方法接收一个函数作为累加器,reduce为数组中的每一个元素依次执行回调函数,接收四个参数:初始值(上一次回调返回的值),当前元素,当前索引,原数组。
语法:reduce(callback, [initialValue]
callbck包含四个参数:
var arr = [1, 2, 3, 4];
var sum = arr.reduce(function(prev, cur, index, arr) {
//调试,实在不明白可以单步调试一下
// debugger
console.log(prev, cur, index,arr);
return prev + cur;
//下面的指定pre的初始值为0
},0)
console.log(arr, sum);
//reduce函数的高级用法,求数组中元素的出现次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let nameNum = names.reduce((pre,cur,index)=>{
console.log(pre,cur,index)
if(cur in pre){
pre[cur]++
}else{
pre[cur] = 1
}
console.log(pre,cur,index)
return pre
},
//这里设置pre初始值是空对象
{})
console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
1.get请求
Query String Parameters
GET请求时,参数会以url string 的形式进行传递,即?后的字符串则为其请求参数,并以&作为分隔符。
2.1post请求,第一种请求体FormData
当发起一次Post请求,若未指定Content-type,则默认content-type为application/x-www-form-urlencoded,即参数会以FormData的形式进行传递,不会显示出现在请求URL中。
2.2post请求,第二种请求体Requset Payload
当发起一次post请求,若Content-Type为application/json,则参数会以Request Payload的形式进行传递(数据格式为json),不会显示出现在请求url中。
在vue里面,组件通讯是重中之重。好的通讯方式无疑让代码更加简洁优化,而provide / inject
就是组件通讯的一种,可以实现父子组件,或父组件和后代组件的通讯。
1.
provide 在父组件使用,使用时和data等属性平级使用。它负责提供需要传递的数据,只能为一个对象或者一个返回对象的函数。
export default {
name: "icfTaskTodo",
data() {
return {
tabArr: [],
initIndex:
this.$route.query.showTab === "TODO"
? "1"
: this.$route.query.initIndex ||
this.$route.params.initIndex ||
"1",
currenttabIndex: 0,
};
},
provide() {
return {
queRecordPage: this.queRecordPage,
};
},
components: {
querySearch,
queryTable,
},
created() {
this.queryTaskTotal();
this.queRecordPage();
},
methods: {
//查询工作台任务
queRecordPage: debounce(function (current, size) {
//工作任务类型(待领取/已领取/已完成)
var queryType = "draft";
switch (this.initIndex) {
case "0":
queryType = "draft";
break;
case "1":
queryType = "assigned";
break;
case "2":
queryType = "completed";
break;
}
if (this.$refs.queryTable) {
this.$refs.queryTable[this.currenttabIndex].queryObj.current =
current;
this.$refs.queryTable[this.currenttabIndex].queryObj.size =
size;
}
let params = {
size,
current,
queryCondition: {},
};
if (this.$refs.querySearch) {
params.queryCondition = Object.assign(
{},
this.$refs.querySearch[this.currenttabIndex].query
);
params.queryCondition.appType = params.queryCondition.appType
? [params.queryCondition.appType]
: null;
}
this.fnBlockLoading(async () => {
let res = await this.$http.post(
`/workflow-web/icfwkfl/workbench/listPage?queryType=${queryType}`,
params
);
this.tableList = res.records || [];
this.total = Number(res.total);
});
}),
},
};
2.inject出现在子组件或者后代组件里,负责将接收到数据注入到这个vue
实例里面。一般来说它直接为一个字符串数组,里面的字符串元素表示注入的数据。
-
任务编号
-
摘要
-
流转环节
-
申请类型
防抖函数:防抖动是将多次执行变为最后一次执行
export const antiShake = (fn,t) => {
let delay = t || 500
let timer
return function(){
let args = arguments;
if(timer){
clearTimeout(timer)
}
let callNow = !timer
timer = setTimeout(() =>{
timer = null
},delay)
if(callNow) fn.apply(this.args)
}
}
//vue页面引入防抖方法
import { antiShake } from "@/utils/index"
//exportDerived方法为按钮点击事件
exportDerived: antiShake(function (){
})
节流函数:节流是将多次执行变成每隔一段时间执行。
点击
实际点击:{{ clicknumber }}
有效点击:{{ num }}
function throttle(fn, interval) {
// 1.记录上一次的开始时间
let lastTime = 0
// 2.事件触发时, 真正执行的函数
const _throttle = function(...args) {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
// 2.3.真正触发函数
fn.apply(this,args)
// 2.4.保留上次触发的时间
lastTime = nowTime
}
}
return _throttle
}
1.数组的解构赋值
let arr = [0,1,2]
let [a,b,c]=arr
console.log(a)//0
console.log(b) //1
console.log(c) //2
2.对象的解构赋值
对象的属性则是无序的,所以对象的解构赋值简单理解就是等号的左边和右边的解构相同
let {name,age} = {name:"swr",age:28}
console.log(name)//'swr'
console.log(age) //28
${ }
用``包裹起来Const name = '小缘'
const age = 14
console.info(`大家好,我叫${name},今年${age}岁了`)
// 等价于
console.info('大家好,我叫' + name + ',今年' + age + '岁了')
// 最大的优势是支持换行字符串
Const url = '//baidu.com'
Const text = '百度一下,你就知道'
Const html = `
`
console.log(html)
console.log(typeof html)
1.Map
是一个特殊的对象,将键与值相关联。键可以是任何基本类型(通常是 string
,但可以是 number
等)。
幸运的是,Map
也是可迭代的(在键/值对上进行迭代),并且 for...of
可以轻松地循环迭代所有键/值对。
2.for (const [number, name] of names)
迭代 names
的键值对。
在每个循环中,迭代器都会返回一个数组 [key,value]
,并使用 const [number,name]
立即对这对数组进行解构。
const names = new Map();
names.set(1, 'one');
names.set(2, 'two');
for (const [number, name] of names) {
console.log(number, name);
}
// logs 1, 'one'
// logs 2, 'two'
3.Object.entries(person)
返回一个键和值的元组数组:[[''name','John Smith'],['job','agent']]
。然后,使用 for...of
循环遍历数组,并将每个元组解构为 const [prop,value]
const person = {
name: 'John Smith',
job: 'agent'
};
for (const [prop, value] of Object.entries(person)) {
console.log(prop, value);
}
// 'name', 'John Smith'
// 'job', 'agent'
1.vuex的state和vue的data有很多相似之处,都是用于存储一些数据,或者说状态值.这些值都将被挂载 数据和dom的双向绑定事件,也就是当你改变值的时候可以触发dom的更新.
虽然state和data有很多相似之处,但state在使用的时候一般被挂载到子组件的computed计算属性上,这样有利于state的值发生改变的时候及时响应给子组件.如果你用data去接收$store.state,当然可以接收到值,但由于这只是一个简单的赋值操作,因此state中的状态改变的时候不能被vue中的data监听到。
2.Vuex 允许我们在store中定义“getter”(可以认为是store的计算属性)。就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
getters的作用
对于getters的理解主要作用是对state属性进行计算,可以理解类似于Vue中computed。
1.table.vue
ref="table"
:height="tabContentHeight"
export default{
data(){
isAccordion:false//是否折叠
tabContentHeight :200
},
methods:{
getOffTop(){
this.isAccordion = !this.isAccordion; //true为折叠
if(this.isAccordion == true){
setTimeout(() == {
this.setTabContentHeight("table","showPage","accordion");
},200)
}else{
setTimeout(() == {
this.setTabContentHeight("table","showPage","");
},300)
}
},
//设置自适应table表格高度,getEIOffsetTop为全局自适应表格方法
setTabContentHeight(refName,showPage,accordion){
this.$nextTick(){
this.tabContentHeight = `calc(100vh - ${this.getEIOffsetTop(
refName,
showPage,
accordion
)})`;
this.$refs.table.doLayout();//表格列错位纠正方法
}
}
}
}
2.main.js
import Vue from "vue"
import ElementUI from "element-ui"
Vue.use(ElementUI);
import {getEIOffsetTop} from "@/utils/tools.js"//引入方法所在的JS
Vue.prototype.getEIOffsetTop = getEIOffsetTop //注册全成局方法
3.tools.js(存放公共方法的js) getBoundingClientRect检测元素距离顶部的距离
export function getEIOffsetTop(refName,isShowPage,accordion,tableBoxHeight){
if(this.$refs[refName]){
if(isShowPage && isShowPage == 'isShowPage' && accordion == ''){
return this.$refs[refName].$el.getBoundingClientRect().top + 10 + 63 + 'px';
} else if(accordion == 'accordion'){
return this.$refs[refName].$el.getBoundingClientRect().top + 10 + 'px';
}
}
}
1.table表格中获取的多条数据截取逗号并换行显示内容
import Vue from "vue"
import ElementUI from "element-ui"
Vue.use(ElementUI);
import {cutout} from "@/utils/tools.js" //引入方法所在的JS
Vue.prototype.cutout= cutout //注册全成局方法
export function cutout(cellValue){
if(cellValue){
return cellValue.replace(/,/g, '')
}else{
return cellValue
}
}
2.table表格自适应
1.src/margin/js
import Vue from "vue"
import ElementUI from "element-ui"
Vue.use(ElementUI);
import {getEIOffsetTop} from "@/utils/tools.js"//引入方法所在的JS
Vue.prototype.getEIOffsetTop = getEIOffsetTop //注册全成局方法
export function getEIOffsetTop(refName,isShowPage,accordion,tableBoxHeight){
if(this.$refs[refName]){
if(isShowPage && isShowPage == 'isShowPage' && accordion == ''){
return this.$refs[refName].$el.getBoundingClientRect().top + 10 + 63 + 'px';
} else if(accordion == 'accordion'){
return this.$refs[refName].$el.getBoundingClientRect().top + 10 + 'px';
}
}
}
2.@keyup方法鼠标浮点数补0,@blur方法鼠标离开
improt {floatPointBlur} from "@/utils/tools.js"
export function floatPointBlur(val){
if(val != ""){
return val.indexOf(".") > 0?
val.replace(/\.\d*/i,(item) => {
return item.length === 1 ? item + "00" : (item.length === 2 ? item + "0" :
item);
}) : val + ".00";
}
}