vue起步

基础

template标签里,一定要有一层父级元素包裹住内容,不一定得是div标签,也可以是其他的,否则会报错
style标签里写样式时,加上scoped,则当前样式只适用于局部这个vue组件,否则适用于全局
vue一般是用数据驱动视频渲染,即很少在html中书写中文,一般是在data的return中定义数组,然后在html中用v-for来遍历数组以渲染json对象
mounted(){}里面写的东西,是挂载完成以后自动执行
当使用export default时,import时不加花括号;使用export时,import时要加花括号


class属性妙用

什么时候绑定class属性:例如以下情况,:class="{ 'active' = isActive }" (在style中写.active的样式,若isActive为true则class就会为active,然后该标签的内容会被样式渲染;冒号即为v-bind的缩写),为什么说这里是绑定呢,因为在data的return里写了isActive=true,然后在html里用了这个值,实现动态绑定效果

一个进阶一点的用法如下 :class="{ 'active' : isActive == index }" v-for="(item,index) in array" 然后在data的return里写isActive: 1 那么只有array数组中的第2个item元素会被active样式所渲染

再给一种用法 v-for="(item,index) in array" :class="{'active': item.current}" 然后在array数组里面给每一个item按是否要渲染写上它们的current值,array:[{txt:'登录',current:true},{txt:'注册',current:false}]

再给一种用法 v-for="(item,index) in array" :class="{'active': item.current}" @click="toggleMenu(item)" 然后在methods里面写toggleMenu(data){this.array.forEach( elem => {elem.current = false}); data.current = true}
这里有两个要注意的点,一是我们在html里面把当前的item传进来,然后在method中用data接收,此时传进来的是地址,即我们在method中改变data的current值,是可以影响到数组里面item的值的;二是注意这个toggleMenu方法的两个步骤,第一步我们用一个forEach方法,把array数组中所有对象的current值初始化为false,然后第二步再给当前传进来的这个item赋true值,以此达到效果点击哪个item它就被渲染,而且是可以不断改变选择的


在哪里写js方法

在utils(存放工具类函数)文件夹里创建validate.js文件,然后在里面写上stripscript(str){……}方法用于过滤特殊字符,注意要在该方法前加上export将方法暴露出去,这样当我们在某个vue文件里写校验时要用到这个方法,就在script标签里写上import{ stripscript } from '@/utils/validate.js',然后就可以直接用该方法了
这里有个注意的点,@在路径里代表什么呢,可以在vue.config.js(一个可选的配置文件)里面找,里面alias写了各种简写符号代表的是什么路径,发现@表示当前的src;拓展一下,配置文件里面的extensions可以自动添加文件名后缀,因此上面引用就可以简写为import{ stripscript } from '@/utils/validate' 也不会报错;再拓展一下,修改完vue.config.js一定要把项目重启一遍才会生效

resolve: {
        extensions: [".js", ".vue", ".json"], //文件优先解析后缀名顺序
        alias: {
          "@": path.resolve(__dirname, "./src"),
          "@c": path.resolve(__dirname, "./src/components"),
          "@v": path.resolve(__dirname, "./src/views"),
          "@u": path.resolve(__dirname, "./src/utils"),
          "@s": path.resolve(__dirname, "./src/service")
        }, // 别名配置
        plugins: []
      }

v-if与v-for妙用

v-if 为false时,直接删除DOM元素(这里要区别于v-show,它只是在元素中添加display,隐藏DOM元素);注意,当DOM元素中有接口时,v-if为true会请求接口
下举一个v-show的例子 在html的标签中,用上v-show="model === 'register'" v-for="(item,index) in array" @click="toggleMenu(item)" 然后在data的return里写上 model : 'register',array:[{txt:'登录',current:true,type:'login'},{txt:'注册',current:false,type:'register'}] 在methods中写 toggleMenu(data){ this.model=data.type } 注意,标签是否显示取决于模块值model是否为register,且默认显示;当发生点击事件,模块值发生改变,达到隐藏该标签的效果


vue3.0语法

在vue3.0的语法中,我们把data数据、生命周期、自定义的函数全部写在setup方法里面了

setup(props,context){
	context.attrs
	context.slots
	context.parent
	context.root
	context.emit
	//而在2.0的语法中,我们会写成this.$attrs
}

比如说上文我们在data的return中声明了一个对象 array数组,基础数据类型 model,那么现在我们就把它们的声明写在setup方法里面

setup(){
	const array = reactive([
		{txt:'登录',current:true,type:'login'},
		{txt:'注册',current:false,type:'register'}
		])
	const model = ref('register')
}

注意这里的reactive方法,只要是声明一个对象的话,都必须用该方法处理;若声明的是基础类型变量,则用ref方法处理;还有,必须在script里写上,import { reactive,ref } from '@vue/composition-api';还有一个要注意的点,要取到基础类型数据的值,必须写model.value才可以,比如model.value = 10对象类型不需要哦,只要写对象变量名即可
拓展: console.log(isRef(model) ? true : false)用于判断是否为ref类型
函数同样在setup里面声明

setup(){
	const toggleMenu = (data => {
	array.forEach( elem => {
	elem.current = false
	}); //注意这里,3.0中没有this的写法了,直接写变量名即可
	data.current = true
	})
}

注意这样还没完,最后一步,把声明的要在模板中使用的data,生命周期,函数等等全都return出去

setup(){
	return{
		array,
		model,
		toggleMenu
	}
}

axios

首先,下载axios依赖,然后在script中写上import axios from ‘axios’
在网页的console控制台里,选择network,选择XHR,就可以看到我们的请求
我们在上文写到@click="toggleMenu(item),然后我们在toggleMenu方法里用上axios,当点击时就会去请求接口

const toggleMenu = (data => {
	axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
	array.forEach( elem => {
	elem.current = false
	}); 
	data.current = true
	})

注意,无论你是用get,post,delete等等各种方法请求,最终都是来到axios.request;因此我们可以全都用request方法来写,然后在method中进一步选择get,post等等,如下

const toggleMenu = (data => {
	axios.request({
	// `url` 是用于请求的服务器 URL
    url: '/user',
    // `method` 是创建请求时使用的方法
    method: 'get', // default
	})
})

接口的复杂写法

我们在login文件夹里写了index.vue,然后在src中创建一个api文件,里面对应写一个login.js文件,里面就可以写上接口请求,以及引入拦截器,然后回到index.vue,我们在里面import {要用的请求方法名} from ‘@/api/login.js’
我们在vue文件里面调用了js文件里的接口,接口就会去调用拦截器,开始拦截事件处理,拦截器处理完信息后,就会把信息全都返回到vue文件里
注意,拦截器是在request.js里面定义的,接下来我们要自己创建一个axios拦截器,在utils文件夹里创建request.js文件,在里面贴上”创建变量axios,赋给变量instance“的语句,然后贴上文档提供的拦截器写法格式时,注意一定要把axios改成我们自己创建的变量的名字instance

import axios from 'axios'
const instance = axios.create();//创建变量axios,赋给变量instance
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });
  
 export default instance

这里讲一个点:我们在request.js里面写export default instance,然后在api里面的js文件里面写import service from '@/utils/request',然后底下的接口写

service.request({
    url: '/user',
    method: 'get',
	})

这是完全没毛病的,我们在request.js中不过是把这个对象暴露出来,然后我们在api的js文件里把这个对象引用进来,并且重命名了一次


以下给个接口实例:
在这里插入图片描述
在src/api/user.js里我们写接口

import request from '@/utils/ysw-request'

// 查询客户列表
export function listUser(query) {
  return request({
    url: '/user/listDetail',
    method: 'post',
    params: query
  })
}//这里是声明了一个listUser方法,里面返回一个接口请求,并把这个方法暴露出去

// 获取地区信息
export function listArea() {
  return request({
    url: '/region/info',
    method: 'get'
  })
}

然后在src/views/user的各个vue文件里,我们就可以调用它们了

import {
  listArea,
  listUser,
} from '../../../api/user'
methods: {
    getList() {
      this.listLoading = true
      this.listQuery.provinceCode = this.areaCode[0]
      this.listQuery.cityCode = this.areaCode[1]
      this.listQuery.districtCode = this.areaCode[2]
      let query = JSON.parse(JSON.stringify(this.listQuery))
      if(query.subject.length !== 1) delete query.subjectScore
      query.subject = query.subject.join(',')
      if(query.subjectScore === '') delete query.subjectScore
      listUser(this.listQuery).then(res => {
        const data = { res }
        this.listLoading = false
        this.list = data.res.data
      })
    }
}

以下重点写一下拦截器的写法,首先必须了解一下vue的环境变量
在项目根目录中放置下列文件来指定环境变量

.env                # 在所有的环境中被执行
.env.local          # 只在本地环境上做测试,不会被提交到代码仓库上去
.env.[mode]         # 只在指定的模式中被载入
.env.[mode].local   # 只在指定的模式中被载入,但会被 git 忽略

再来讲三种模式

development 模式	用于 vue-cli-service serve,即我们的开发模式
test 模式			用于 vue-cli-service test:unit,即我们的生产模式,已经发布在线上可以使用的模式
production 模式		用于 vue-cli-service build 和 vue-cli-service test:e2e,测试模式,用得少

对于模式我们要记住几个点,一个模式可以包含多个环境变量
怎么声明?通过.env文件加后缀来声明,比如说,我们在根目录创建一个.env.development的文件,那么在这个文件里面声明的变量就只会在development模式下被载入;比如说,vue-cli-service build 会加载可能存在的 .env、.env.production 和 .env.production.local 文件然后构建出生产环境应用
还有,模式的名称是有标准写法格式的,NODE_ENV的值,就是用来决定你运行的模式是开发、生产、还是测试的,在 production 模式下被设置为 “production”,在 test 模式下被设置为 “test”,默认则是 “development”
还有,我们在每个模式里是默认就有这个NODE_ENV的值的
在vue.config.js里面,我们可以把这个值打印出来看

module.exports = {
  publicPath: process.env.NODE_ENV === "production" ? "/" : "/"
}

举例子:
在这里插入图片描述
.env.development里面声明了以下环境变量,这是在开发环境下会被执行的文件

# 开发环境配置
ENV = 'development'
# 时肆教育管理系统/开发环境
VUE_APP_BASE_API = '/occam-api'
# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true

.env.production里面声明了以下环境变量,这是在生产环境下会被执行的文件

# 生产环境配置
ENV = 'production'
# 时肆教育管理系统/生产环境
VUE_APP_BASE_API = '/occam-api'

这里要注意一个点,环境变量的命名规范,前面的VUE_APP是固定的,后面加的_BASE_API才是我们自定义的名称
如何打印出来看值?

console.log(process.env.NODE_ENV)//打印出来development
console.log(process.env.VUE_APP_BASE_API)

这样分文件定义环境变量有什么用处呢,同一个变量我们在两个环境的文件里可以取不同的值,那么我们发布上线,或者平时测试,系统就会自动去切换这个变量的值了,我们用它的变量名即可


说完模式与环境变量,接下来来讲拦截器
第一步:自定义axios拦截器,配置baseURL,即前端API地址

const instance = axios.create({
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000,
  headers: {'X-Custom-Header': 'foobar'}
});

给个项目实例

const service = axios.create({
  // axios中请求配置有baseURL选项,表示请求URL公共部分
  // baseURL: process.env.VUE_APP_BASE_API,
  baseURL: config.host,
  // 超时
  timeout: 60000
})

然后我们看到config.js里面写到

export default {
  host : 'https://dev.api.wx.occamedu.com/occamapi'
  // host: 'https://test.api.wx.occamedu.com/occamapi',
  // host: 'https://api.wx.occamedu.com/occamapi',
}

这样根据注释去换host的值,我们就可以请求到不同模式的地址了
第二步:解决跨域问题,即在vue.config.js里面配置proxy
在网上搜索axios 跨域,我们得到以下代码:

proxyTable: {
       //axios跨域改造 by zhengkai.blog.csdn.net
      '/api': {
        target:'http://localhost:8888/cert/', // 你请求的第三方接口
        changeOrigin:true, // 在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题
        pathRewrite:{  // 路径重写,
          '^/api': ''  // 替换target中的请求地址,也就是说/api=/target,请求target这个地址的时候直接写成/api即可。
        }
      }
    },

我们把baseURL粘贴到target里面,作为API服务器的地址
拓展一个小知识,当我们在正式服上面运行时,该地址后面会系统自带一个/api,这样就会与我们在跨域里写的’/api’名称搞乱,这里我们自己起的的/api等价于target的地址,所以一般会自己改个名字,比如说改成devApi
捋一下这里的逻辑,我们自己起的’/api’ === ‘http://localhost:8888/cert/’(target里的地址)
给个例子,我们在request.js里面写拦截器

const BASEURL = process.env.NODE_ENV === 'production' ? '' : '';
const service = axios.create({
  baseURL: BASEURL,
  timeout: 60000
})

这样子跑出来baseURL是本地端口/api,这里的/api等价于target的地址
即http://192.168.0.106:8080/api/ = ‘http://localhost:8888/cert/’
那么底下pathRewrite的’^/api’是干什么用的,是转向用的,它是一个正则表达式,表示查找我们本地服务运行起来时的api字符串,并将其用后面的值覆盖掉

再给项目实例

proxy: {
      // detail: https://cli.vuejs.org/config/#devserver-proxy
      [process.env.VUE_APP_BASE_API]: {
        // target: `https://secretary.occamedu.com/occam-api`,
        target: `https://dev.secretary.occamedu.com/occam-api`,
        // target: `https://test.secretary.occamedu.com/occam-api`,
        // logLevel: 'debug',
        // target: `http://localhost:9001/occam-api`,
        changeOrigin: true,
        pathRewrite: {
          ['^' + process.env.VUE_APP_BASE_API]: ''
        }
      }
    },

拓展一下,拦截器这里的timeout: 60000,意思是当我们网络请求接口超过6秒中还没成功,那么将请求失败,执行Promise.reject


讲一下Promise
写法如下:(resolve,reject)这是作为两个参数

let promise = new Promise((resolve,reject) => {

})//声明完,我们就可以回调两个常见方法
promise.then(response => {
}).catch(error => {
})

最简单的理解,当我们Promise这边调用resolve()方法时,底下promise就回调.then(response => {})这一块,同理当Promise这边调用reject()方法时,底下promise就回调.catch(error => {})这一块,一一对应
举个例子

let promise = new Promise((resolve,reject) => {
	reject()
})
promise.then(response => {
	console.log("成功")
}).catch(error => {
	console.log("失败")
})

明显跑起来后控制台就会出现失败二字

let promise = new Promise((resolve,reject) => {
	resolve(123)
})
promise.then(response => {
	console.log("成功")
	console.log(response)
}).catch(error => {
	console.log("失败")
})

传入参数后,response将会接受到值,打印出123

进阶一下,声明一个psomise方法

function psomise(status){
 	return new Promise((resolve,reject) => {
 	if(status) {
 		console.log("promise成功")
 		resolve("promise返回数据成功")
 	}
 	if(!status) {
 		console.log("promise失败")
 		resolve("promise返回数据失败")
 	}
})
}

我按以下代码回调,控制台将出现promise成功

promise(true).then(response => {
	
}).catch(error => {
	
})

我按以下代码回调,控制台将出现promise成功 promise返回数据成功

promise(true).then(response => {
	console.log(response)
}).catch(error => {
	console.log(error)
})

再进阶一下,写一个链式的调用,我们定义promise1和promise1两个funuction

function psomise1(status){
 	return new Promise((resolve,reject) => {
 	if(status) {
 		console.log("第一个promise成功")
 		resolve("第一个promise返回数据成功")
 	}
 	if(!status) {
 		console.log("第一个promise失败")
 		resolve("第一个promise返回数据失败")
 	}
})
}
function psomise2(status){
 	return new Promise((resolve,reject) => {
 	if(status) {
 		console.log("第二个promise成功")
 		resolve("第二个promise返回数据成功")
 	}
 	if(!status) {
 		console.log("第二个promise失败")
 		resolve("第二个promise返回数据失败")
 	}
})
}

然后我们按以下代码回调,控制台显示第一个promise成功 第一个promise返回数据成功 第二个promise成功

promise1(true).then(response => {
	console.log(response)
	promise2(true)
}).catch(error => {
	console.log(error)
})

然后我们按以下代码回调,控制台显示第一个promise成功 第一个promise返回数据成功 第二个promise成功 第二个promise返回数据成功

promise1(true).then(response => {
	console.log(response)
	promise2(true)
}).then(response => {
	console.log(response)
}).catch(error => {
	console.log(error)
})

这样当我们要写很多方法嵌套来嵌套去的时候,我们在声明function时可以独立分开声明,我们在执行回调时使用promise来链式使用,达到分离效果


了解完promise的回调基础后,我们再来讲拦截器里面的细节

// 添加请求拦截器
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);
  });

当我们写以下代码时,接口响应传进来的数据全部在控制台打印出来//我们在服务器请求了相关的数据回来之后,在响应拦截这里做一些事情

axios.interceptors.response.use(function (response) {
    console.log(response)
    return response;
  }, function (error) {
    return Promise.reject(error);
  });

我们也可以这么写

axios.interceptors.response.use(function (response) {
    let data = response.data
    if(data.resCode !== 0){
    	console.log("有错")
    	return Promise.reject(data);
    }
    else{
    	return response
    }
    return response;
  }, function (error) {
    return Promise.reject(error);
  });

我们在服务器请求了相关的数据回来之后,在响应拦截这里若出错了,返回Promise.reject(data),然后返回到api的方法接口那里,然后返回到vue那里,我们在vue那个方法接口那里,用上.then与.catch,就可以把参数回调进来在前台显示

给个实例:(GetSms是个接口名,root.$message是el组件)

GetSms(requestData).then(response =>{
	let data = response.data
	root.$message({
		message: data.message,
		type: 'success'
	}).catch(error =>{
		
	})
})

前面拓展过timeout,这里讲一下setTimeOut方法,其实就是一个时间延时效果,先延迟自定义的时间,再执行一次方法(注意这里的一次,区别于setInterval,它会隔一段延迟的时间,就执行一次,只有在某个条件下才会停止)

setTimeOut(() => {
	GetSms(requestData).then(response =>{
		let data = response.data
		root.$message({
			message: data.message,
			type: 'success'
		}).catch(error =>{
			
		})
	})
}, 300)
//实现延迟3毫秒

然后讲一下停止定时器的方法,对应clearTimeOut(定时器变量名称)和clearInterval(变量)

这里我们来写一个倒计时的方法

const countDown(() => {
	setTimeout(() => {
		console.log(一秒后只执行一次)
	},1000)
	setInterval(() => {
		console.log(每隔一秒执行一次)
	},1000)
})

先声明好timer,用的时候传60s进去,countDown(60)

const countDown((number) => {
	let time = number
	timer.value = setInterval(() => {
		time--
		console.log(time)
		if(time === 0){
			clearInterval(timer.value)
		}else{
			codeButtonStatus.text = '倒计时${time}秒'  //注意这里等价于‘倒计时’+time+‘秒’,不过是es6的写法而已,简便建议多用!
		}
	},1000)
})

如何联调

前后端同时打开服务器,然后连在同一个局域网上
前端拦截器处,把baseURL改为后端的ip地址,再加上端口号,然后就可以在不部署接口到服务器的情况下进行接口请求了
举个例子:
在这里插入图片描述
就是这个baseURL
在这里插入图片描述


前端post请求get请求内–body和query传参的区别

https://www.cnblogs.com/chr506029589/p/12987356.html
传的时候看清楚后端要的是body还是query
在这里插入图片描述
在这里插入图片描述


前后端敏感数据加密

https://www.cnblogs.com/king94Boy/p/12987905.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值