This is my vue develop exprience~
2020/5/7 16:02 Write
过往项目经验总结
关键词:Vue,CSS,SVN,WebPack,IconFont,Flex,Jeecg,Iview,ElementUI
1 2 3 4 5 6 7 8
| 使用Vue开发页面,环境配置,导入包,Package,使用IView组件进行页面开发。 (使用开源组件一定需要查看开发文档!!!!!!) CSS排版布局,flex学习并使用,各种定位的深入了解。 router路由在Vue当中的使用,熟练使用组件进行开发。 熟练使用SVN进行提交和更新代码,提交需要带钩子,如果本地有更改过的文件,在更新时需要将有改动的文件删除再更新,否则会出现乱码 父子组件间的传值通信,Props的使用,对话框的熟练使用。 分析需求并设计页面,使用Axure进行页面的设计,使用开源的移动端组件和阿里的IconFont,必要时可以自行设计组件。 熟悉WebPack框架和Cli脚手架。
|
1 2 3 4
| 使用ant-design-jeecg-vue进行开发,代码自动生成。文档链接:[jeecg开发文档]("http://doc.jeecg.com/1273969") 该框架生成的代码由ElementUI组件组成。 考虑页面的逻辑和合理性。 弹框嵌套,需要注意层级。
|
2020/5/7 10:33 Write
使用Vue进行对应页面开发
1 2 3 4 5 6 7 8 9 10
| 使用elementUI进行页面的开发,使用Upload上传文件,自带判断文件后缀。 使用POST方法,带FormData参数,使用Append添加序列,需要New一个FormData对象,然后进行传参。 使用Dialog组件,显示设备详情,点击跳出,准备参析路由。 GET方法带的参数只有Params对象。跟在URL后面。 POST和GET不同://都为TCP链接,并无差别。 参数格式不同以外,参数的大小也不同。因为服务器的处理方式不同,不一定能接受到数据(request body的数据)。 由于HTTP的规定和浏览器/服务器的限制,应用过程体型出不同。 GET产生一个TCP数据包,POST产生两个TCP数据包。 GET,header和data一起发过去,响应200。(返回数据) POST,先发送header,服务器响应continue,再发送data,响应200。( 返回数据)
|
2020/5/7 15:53 Write
使用Element组件遇到的问题~
1 2 3 4 5
| 使用elementUI的UpLoad组件上传xls文件,需要注意文件格式和文件获取 组件自带上传,可以设置header和数据的name,需要注意Token或者Cookie 组件获取文件的方式 this.$refs.{upload}(这是关联upload组件的ref名称).$data.uploadFiles 注意dialog组件的visible显示值设置 详细查看开发文档!!!!!必要时进行测试获取信息!!
|
2020/5/8 9:38 Write
使用SVN合并代码,并开发模式遇到问题
1 2 3 4 5
| 将文件checkout在其他文件夹里,然后修改原代码文件。 多注意NetWork中请求的格式,请求的参数格式!!!! 其中GET方式的URL会随参数改变,POST方式不会。 使用POSTMan测试。 接口文档管理有使用到SWAGGER和小幺鸡~
|
2020/5/9 9:53 Write
总结工作经验,编写简历
1 2 3 4 5
| Vue的两种路由模式:Hash和History模式 hash:默认模式 常用NewURL和OldURL来改变链接,动态页面数据。hash值发生变化的时候,会触发hashchange这个时间,通过该事件监听hashchange来实现更新页面部分内容。 History模式: 切换历史状态,back,forward,go三个方法,刷新页面会请求服务器。History模式需要避免刷新。刷新时如果没有相应的响应或者资源,会刷新出404。
|
1
| 同事开发地图,使用蜂鸟地图插件。经过询问得知,正在研究。
|
1 2 3
| 回温Vue文档。查看生命周期。 beforeCreate()->created()->beforeMount()->mounted()->beforeUpdate()->updated()->beforeDestroy()->destoryed()//函数调用顺序,中间各有过程 周期如下图
|

1 2 3 4
| 在使用ElementUI的Upload上传文件时,action的动态响应是在上传后执行的,所以需要给上传方法设置延时器,并且用到this上下文的时候,需要将this传到该函数内使用,否则会报错。 上传可以设置header的值,在初始化的时候获取token:this.header = {token:`${this.$cookie.get('token')}`} 设置的header是一个对象,给header的token属性赋值,要求上传成功后自动关闭对话框,然后清除选择文件数据:this.$refs.upload.clearFiles(); 需要考虑功能全面,合理
|
1 2 3 4 5
| vue中数据异步渲染,数据响应式为Vue 的重要核心,在数据变更后,可能DOM还未更新,所以可以调用nextTick(callback)函数,这样回调函数将在DOM更新完后被调用。并且this会绑定到当前的vue实例上。 同域:域名、端口、协议均相同,缺一不可。 跨域:浏览器从一个域名的网页去请求另一个域名的资源时,不同域,就是跨域。//可能会被另一个域保存Cookie或session用来对同域网站发起非法操作,为CSRF攻击,盗用身份。 解决方法:JSONP,CORS。//https://www.jianshu.com/p/f880878c1398(参考) 使用FileZilla Client进行网页部署,连接到服务器,将右边框内dist文件删除,从左边框内选择本体文件,然后右键上传。
|
Vue加载本地图片失败,无法使用相对路径。
//使用绝对路径 :src=”‘https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg‘“
//使用require :src=”require(‘@/assets/images/icon/file/jpg.png’)”
//使用import import jpg from ‘@/assets/images/icon/file/jpg.png’
Vue使用vue-awesome
//执行指令 npm install vue-awesome
//在main.js文件下 import ‘vue-awesome’ || import Icon from ‘vue-awesome/components/Icon’
//Vue.component(‘icon’,Icon) 然后正常使用
Vue使用Iconfont
//选择Icon加入购物车,并且下载源码
//执行命令npm install css-loader -D(否则会报错)
//在main.js文件中引入 import ‘@/assets/Iconfont/iconfont.css’!!!!!注意这里使用@,绝对路径
//直接使用 在iconfont.json文件中查看各个icon的fontclass
Vue行内写hover样式
//onmouseover=”this.style.color=’#57EDED’”!!由于无法实现hover,使用js事件实现,并且在参数边要加引号’’
//改变光标形状为小手:cursor=’pointer’
Vue点击跳转链接
//如果不写协议,会自动在链接前加上localhost:8080(相当于一个相对路径)
CSS3 animaiton 实现图片旋转
//animation: 15s linear 0s normal none infinite rotate;
//animation-play-state: running;
Vue导入本地音频文件
//文件放入static文件里,无需改变任何Webpack配置,直接引入
//引入写法:mp3Url:”static/attack音D.mp3”
Vue js将小数转为整数值
//toFixed(2) 后面的数值代表保留两位小数
Vue 将字符串转化为数值
//parseInt(str) 如果是浮点数,将Int改成float即可
Vue 实现进度条
// element UI 放置 el-progress :percentage=”mp3width” 设置percentage为数值变量
// 实现函数LoadProgress 通过setInterval改变mp3width的值(浮点数)
//使用el-slide,可以实现点击和拖拽
//需要注意函数运行速度,存在未取到值而后直接进行计算
Vue注意事项
//开发到后发现,需要通过数据关联来通过子组件控制父组件。
//还有一些加载速度,值得优化和注意。
Vue遇到组件通信问题
//尽量减少组件层数,如果在同一层父组件时,子组件可以一起和父组件通信,获得数据共享。
深入响应式原理,vue的核心。
当一个对象在实例化中的data选项,Vue将遍历此对象所有的property,转为getter和setter。
每个组件实例都对应有一个watcher实例,在渲染过程中把数据property记录为依赖,之后当setter触发时,会通知watcher,使关联的组件重新渲染。
注意:当数据在data选项外时,为非响应式!!!
数组的长度和直接利用索引直接设置的数据都不是响应性的,这时可以使用set方法,使用index和数组的子项更新数据。
vue提前声明所有的响应式property。
Vue在更新DOM时是异步执行的,侦听到数据变化时,将开启一个队列,缓冲在同一事件循环中发生的所有数据变更。
使用原生html,js,css开发文书模板。
body{padding:0px;margin:0px} //适应浏览器,无白边
使用占位符,空格( ),后用正则表达式替换。
text-align:justify;// 文字两端对齐
margin:0 auto;// 左右对齐
white-space:normal// 文字换行,元素空白处理
div的使用和flex的合理使用
使用远程桌面连接部署,Windows+r运行 mstsc
输入用户名和密码,连接
然后将本地的文件复制并粘贴部署到连接的服务器上
开源项目Vue-element-admin
权限验证:根据用户登录的role去判断角色请求路由表,动态生成可访问页面。路由挂载。
指令权限:通过封装方法,判断角色权限,类似于V-if,不同角色能看到的操作不同。
spa(single page web application 单页面开发)//科普
路由:分动态和静态路由,主要需要注意引入和使用到的地方,需要快速定位代码中使用路由的位置,研究动态路由的实现。
在文件夹中选择find in path 在所有文件中查询使用的地方
将router的path改为“/”为默认跳转的第一页面
vue有三类路由钩子
1.全局钩子 调用router.beforeEach和.afterEach函数 其中next,to中如果带参数,会导致回调,要避免死循环。
2.某个路由的钩子
3.组件内钩子
Vuex使用和了解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| //State computed: { count () { return this.$store.state.count//一般如此调用store的数据 }, ...mapState({ //或者通过mapState函数,批量获取 sidebar: state => state.app.sidebar, device: state => state.app.device, showSettings: state => state.settings.showSettings, needTagsView: state => state.settings.tagsView, fixedHeader: state => state.settings.fixedHeader }), } //Getter getters: { doneTodos: state => { return state.todos.filter(todo => todo.done)//返回处理过的数据 return this.$store.getters.doneTodosCount//直接返回函数运行后返回的对象 } sidebar: state => state.app.sidebar, size: state => state.app.size, device: state => state.app.device } computed: { //依旧在computed辅助函数里调用,mapGetters函数 // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } //mutation 相当于函数,用于改变state的值 store.commit('increment')//调用mutation handler方式 // ... mutations: {//mutation函数,限制函数同步执行 increment (state, n) {//可以传值 state.count += n } } store.commit('increment', 10)//传入值10 mutations: { increment (state, payload) { //一般是传入一个对象 state.count += payload.amount } } const mutations = { SET_TOKEN: (state, token) => { //使用常量来定义函数名 state.token = token }, SET_INTRODUCTION: (state, introduction) => {//同上 state.introduction = introduction } } commit('SET_ROLES', roles)//调用时 commit('SET_NAME', name) //action 类似于mutation,可以在其中调用mutation,可以内部执行异步操作 actions: { //action函数接受一个与store实例具有相同方法和属性的context对象,可以通过该对象获取state和gettersstore.dispatch('increment') increment ({ commit }) { commit('increment') } } store.dispatch('increment')//action函数通过dispatch方法触发 //在action中有设计到登录操作,调用异步API和分发多重mutation 也可使用mapAction //Module 用于将store分割成模块,每个模块拥有自己的state,mutation,action,getter,从上到下分割 在状态数较大时可以使用,避免臃肿。 设置Namespaced:true,使其成为带命名空间的模块,避免冲命名污染。 在全局命名空间内分发action或提交mutation,将root:true作为第三参数传给dispatch或commit,直接访问到root下的函数(数据)。
|
可以在assets文件中放置css文件,或者一些静态文件。在main.js引入,全局调用。
路由在跳转的时候可以传递参数,有三种方式:
方案1
1 2 3 4 5 6 7 8 9
| this.$router.push({//使用方法 path: `/describe/${id}`, )} {//对应配置的路由 path:'/describe/:id', name: 'Describe', component: Describe } this.$route.params.id//调用方法
|
方案二
1 2 3 4 5 6 7 8
| this.$router.push({//使用方法 name: 'Describe', params: { id: id } }) //路由正常配置 $route.params.id//调用方法
|
方案三
1 2 3 4 5 6 7
| this.$router.push({//使用方法 path: '/describe', query: { id: id } }) $route.query.id//调用方法
|
项目菜单栏:通过多个组件组成,使用el-scrollbar组件(在element文档没有标注)
包裹el-menu,自定义sidebar-item组件使用v-for动态生成多个子项,通过v-if来判断子项显示模式,使用render函数返回item组件作为menuitem,使用link组件(通过:is来判断标签类型,v-bind绑定跳转链接)包裹item来作为跳转链接。
mixins混入的使用,其中有函数,数据,并且在每个组件混入的数据都是独立的。(主要作用:代码复用,减少冗余),其中在mixins里的函数命名必须带$_避免引入组件中函数名重复。
scss文件引入其他scss文件,可以调用类型,但无法调用里面的属性和mixins,在main.js引入就可以全局调用,包括引入文件中已经引入的文件。
Item组件使用render函数返回的原因(性能问题)
css3的使用,美化页面。
v-for的使用,需要一个参数(item,i)in(数组或对象),可以生成多个。
布局注意,P标签自占高度,使用a标签,display:block,块级元素,就可以调整高度了。canvas的使用需要研究,图形实现的好方法。
安装prettier自动代码格式化。
通过ps打开图片获取颜色和像素。
Vue项目不同环境打包指令和配置
1.env.js文件中各自有
1 2 3 4 5 6
| 'use strict' module.exports = { NODE_ENV: '"production(生产)"',//testing(测试),development(开发) EVN_CONFIG:'"prod"',//test,dev API_ROOT:'"/apis/v1"'//api代理地址 }
|
2.还需修改package.json文件
1 2 3 4 5 6 7 8
| "scripts": { "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "start": "npm run dev", "build": "node build/build.js", "build:test": "cross-env NODE_ENV=production env_config=test node build/build.js", "build:pre": "cross-env NODE_ENV=production env_config=pre node build/build.js", "build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js" }
|
3.修改config/index.js
1 2 3 4 5 6 7
| build:{ // Template for index.html // 添加test pre prod 三处环境的配制 prodEnv: require('./prod.env'), preEnv: require('./pre.env'), testEnv: require('./test.env') }
|
4.在webpackage.pro.conf.js中使用构建环境参数
1 2 3
| // 个性env常量的定义 // const env = require('../config/prod.env') const env = config.build[process.env.env_config+'Env']
|
5.build.js文件修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 'use strict' require('./check-versions')() // 注释掉的代码 // process.env.NODE_ENV = 'production' const ora = require('ora') const rm = require('rimraf') const path = require('path') const chalk = require('chalk') const webpack = require('webpack') const config = require('../config') const webpackConfig = require('./webpack.prod.conf') // 修改spinner的定义 // const spinner = ora('building for production...') var spinner = ora('building for ' + process.env.NODE_ENV + ' of ' + process.env.env_config+ ' mode...' ) spinner.start() //更多的其它内容,不需要做任何调整的内容 ...
|
6.打包指令
npm run build:test//测试环境
npm run build:prod//生产环境
以此类推
异步加载:async,defer,动态创建script标签
异步任务:promise,async
8中数据类型分别是:
Number,String,Boolean,Null,undefined,object(data,function,array),symbol,bigInt
Null只有一个值,是null,不存在的对象。
Undefined只有一个值,是undefined,没有初始化,undefined是从null中派生出来的。
Undefined是没有定义的,null定义了但是为空。
基本类型的变量是存放在栈内存(stack)里的
基本类型的值是按值访问的
基本类型的值是不可变的
基本类型的比较是它们的值的比较
类型方法
运算符优先级参考链接表
柯里化:接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下参数并且返回结果的新函数。
1 2 3 4 5 6 7 8 9 10 11
| // 普通的add函数 function add(x, y) { return x + y }
// Currying后 function curryingAdd(x) { return function (y) { return x + y } }
|
数组常用方法(array):
1.concat(arrA,arrB,…)//合并数组
2. arr.join(separator)//数组转字符串
3.arr.toString //无参数,转字符串
4.arr.toLocaleString//以逗号隔开输出
5.arr.slice(start,end)//截取数组
6.arr.splice(index,many,【item1】)//数组删除/添加
7.arr.unshift(x,y)//头部增加
8.arr.shitf()//头部删除
9.arr.push(x,y)//尾部增加
10.arr.pop()//尾部删除
11.arr.sort(sortby) //按字符编码进行排序
12.arr.reverse()//数组颠倒
13.arr.filter()//数组过滤
字符串常用方法(string):
1.str.charAt(index)//返回指定位置的(字符)!!
2.str.indexOf(value,[index])//从index找,返回value第一次出现的下标
3.str.match(value)//存放匹配结果的数组
4.str.split(separator,[many])//数组在separator指定的边界处分割字符串
5.str.search(str)//第一个与str匹配的子串起始位置
6.str.slice(start,end)//按下标截取字符串
7.str.substr(start,[length])//返回从start开始的len个字符
8.str.substring(start,[stop])//提取start到stop的字符串
9.str.concat(x,y,z)//连接字符串
10.str.replace(substr,replacement)//替换字符串中的部分
11.str.toLowerCase()//变小写
12.str.toUpperCase()//变大写
数组循环方法:
forEach(),for-of
引用类型:
Object,Array,RegExp,Date,Function
引用类型的值是保存在堆内存(heap)中的对象(object)
引用类型的值是按引用访问的
引用类型的值是可变的
引用类型的比较是引用的比较
深浅拷贝
浅拷贝为引用,深拷贝为创建一个相同的新对象。
异步和同步
1.同步任务在主线程上形成一个执行栈
2.主线程外还有一个任务队列
3.一旦“执行栈”里的任务执行完毕,系统会读取任务队列里的任务执行
4.主线程重复以上三个步骤
heap(堆)stack(栈)
任务队列中可以放置定时事件(setTimeout,setInterval)
定时器将事件插入任务队列,等执行栈执行完才能去执行指定的回调函数
使用setInterval()循环,在mounted函数中使用。
1 2 3 4 5
| data:{timer:''} this.timer = setInterval(()=>{此处写函数},3000)//1000为1s beforeDestroy(){ clearInterval(this.timer)//在页面销毁前关闭计时器 }
|
使用store
创建新文件timer.js用来设置计时器
在index.js主store中引入
1 2 3 4 5 6 7
| import timer from './modules/timer' const store = new Vuex.Store({ modules:{ timer } }) export default store //暴露,可以外部引入
|
在js文件中,需要引入store ///import store from ‘./store’
直接调用store即可// store.state.clock//store.commit(‘set_clock’,1)
在组件当中调用//this.$store.dispatch对应action(异步)
//this.$store.state对应对象
//this.$store.commit对应mutation(同步)!!只有mutation可以改变状态
//this.$store.getters对应getter //挂载数据计算功能(里面可有数据计算函数)
路由监听:
permission文件当中使用的this.$router.beforeEach(to,from,next)=>{}是全局监听路由的方法
vue页面中有三种监听路由的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 1.watch:{ $route:{ handler(val,oldval){ console.log(val);//新路由信息 console.log(oldval);//老路由信息 } deep:true//深度观察监听 } } 2.watch:{ $route(to,from){ console.log(from.path)//从哪来 console.log(to.path)//到哪去 } } 3.methods:{ getpath(){ console.log(111) } } watch:{ '$route':'getPath' }
|
js数组对象为指针,修改需要深拷贝,否则会修改原数据
防抖:防止按钮多次点击
封装防抖函数:debounce.js
let timeout = null
function bounce(fn,wait) {
if(timeout !== null) clearTimeout(timeout)
timeout = setTimeout(fn,wait)
}
引入(import)并使用
bounce(()=>{function},1000)
数组深拷贝:
1.concat():
let copyArray = [].concat(array)
2.slice(idx1,idx2)
let copyArray = [].slice()//无参为拷贝数组
逻辑梳理,设计模式,需求合理,可维护性
在写api请求的时候,可以使用promise与async await同步操作
并且可以后续抓错处理
父子组件传值
父向子传值:单向绑定,父传过来的值无法在子组件中更改。
1.v-bind props
{
fooA:Number //只接受数值类型的参数
fooB:[String,Number] //可以接受字符串和数值类型的参数
fooC:{type:String,required:true} //可以接受字符串的类型,参数必须传入
fooD:{type:Number,default:100} //接受数值类型的参数,默认值为100
fooE:{type:Object,default:()=>{return{message:’’}};//当为对象类型时设置默认值必须使用函数返回
fooF:{validator:function(value){return value >= 0 && value <= 100;}}//使用一个自定义的验证器
fooG:{type:Array,default:function(){return[]}}// 当为数值类型设置默认值时必须使用数组返回
}
利用$refs
ref=”home” //调用子组件函数获值
this.$refs.home.setMsg(this.mgs)//父
setMsg(val){this.msg = val}//子
子向父传值: v-on $emit
this.$emit(“receive”,”value”)//子组件
@receive=”receive”
methods:{receive(val){}}
利用$parent
setMsg(){this.$parent.toValue(this.msg)} //子
toValue(val){this.msg = val} //父
爷传孙:props
:mgs=”msg”//爷
v-bind=”$attrs”//父
props:{mgs:String}//子
孙传爷
this.$emit(“setVal”,this.msg)//孙
v-on=”$listeners”//父
@setVal=”setVal” setVal(val){this.msg = val}
祖组件传后代组件:要求值必须为对象!!!
provide(){return {data:this.dataObj}}//与data同级,祖组件
inject:[‘data’],computed:{()=>{return’${this.data.msg}&{this.data.num}’}}
兄弟组件传值(store)
EventBus可用,调用完必须销毁,否则出bug。
apply:传入两个参数,一个参数数组,一个运行环境,默认Window。
call:传入多个参数,一个 运行环境,其他为参数。
bind:使用多加(),绑定上下文。
三个函数皆为改变上下文this的函数
多熟悉组件间通信,路由间通信。
持续进行编写和开发,经验保存
后续将CSDN博客中的经验总结并转移,并学习更多HEXO使用方式和编写方式