VUE学习总结
VUE基本语法
VUE是基于ES6进行开发的。
VUE安装
1、安装node.js
node.js下载地址:https://nodejs.org/en/download
下载好后,点击安装,一直下一步即可。安装成功后在控制台通过下面命令如果出现版本号,则安装成功。
node -v #查看vue版本号
npm -v #查看npm版本
npm就是一个软件报的管理工具,和linux下的apt软件安装一样。
安装Node.js淘宝镜像加速器(cnpm)
使用cnpm下载镜像会比npm快很多,cnpm是国内镜像。虽然使用cnpm会下载快,但是尽量少用。
#安装cnpm镜像 -g:全局安装
npm install cnpm -g
# 或者使用下面语句解决,npm速度慢的问题
npm install --registry=https://registry.npm.taobao.org
#查看cnpm镜像源
cnpm config get registry
#查看cnpm版本
cnpm -v
安装cnpm成功后,使用cnpm -v 和cnpm config get registry命令。
2、vue-cli
概念:vue-cli是vue官方提供的一个脚手架,用于快速生成一个vue的项目模板。
预先定义好的目录结构及基础代码,就好比我们在创建Maven项目时可以选择一个骨架项目,这个骨架项目就是脚手架,便利于我们开发。
官方文档地址:https://cli.vuejs.org/zh/guide/#cli
参考狂神笔记:https://www.kuangstudy.com/bbs/1355379516364627970
主要功能:
- 统一的目录结构
- 本地调试
- 热部署
- 单元测试
- 集成打包上线
安装背景:
安装node.js环境,安装cnpm淘宝镜像命令
安装vue-cli
sudo npm install vue-cli -g #安装vue-cli
vue list #得到官方推荐的模板
vue -V #查看vue版本
安装vue-cli成功后,通过vue-v和vue list可以查看版本和支持模板信息
创建vue项目
vue init webpack myvue #创建一个webpack模板的myvue前端工程
npm install #进入myvue项目目录下,执行npm install安装依赖环境
npm install --legacy-peer-deps #如果npm install报错使用该命令代替
npm run dev #启动项目
npm install是根据package.json文件下载依赖环境,npm install安装成功后项目会多一个node_modules目录
npm run dev启动项目
启动项目后通过http://localhost:8080可以访问主页
3、webpack
webpack作用是将js、css、less和sass这类静态资源打包成静态文件,减少前端页面转换。简单来说就是将前端多个静态资源,根据规则生成一个静态资源。
webpack官网:https://webpack.docschina.org/
webpack安装:
npm install webpack -g #全局安装webpack
npm install webpack-cli -g #全局安装webpack-cli
npm install -g webpack webpack-cli #全局安装webpack和webpack-cli,如果npm下载不了,使用cnpm
npm install -d webpack webpack-cli #局部安装webpack和webpack-cli,如果npm下载不了,使用cnpm
webpack -v #查看webpack版本
#webpack-cli是webpack的依赖,要使用webpack打包必须安装webpack-cli
使用webpack打包简单案例:
- 1、创建vue-demo3目录,通过npm init -y将目录转换为一个前端项目,此时目录中会生成一个package.json文件。
- 2、后续我们在vue-demo3项目下创建src目录,并且创建main.js、utils.js和common.js文件,其中main.js是入口文件。
main.js文件:
//将所有的js文件进行引入到一个文件中
const common = require('./common');
const utils = require('./utils');
utils.info('Welcome LiuJun go to Hello world!');
common.info('Hello world!' + utils.add(100, 200));
utils.js文件:
exports.info = function (str) {
//往浏览器输出
document.write(str);
}
common.js文件:
exports.add = function (a, b) {
return a + b;
}
- 3、创建webpack打包配置文件webpack.config.js文件
webpack.config.js文件:
const path = require("path"); //Node.js内置模块
module.exports = {
devServer: {
open: true,
host: '127.0.0.1',
port: 8888,
//设置devServer开发服务器静态资源目录
//默认为项目的根目录(与package.json同路径)
contentBase: path.join(__dirname, './')
},
entry: './src/main.js', //配置入口文件
output: {
path: path.resolve(__dirname, './dist'), //输出路径,__dirname:当前文件所在路径
filename: 'bundle.js' //输出文件
}
}
//执行webpack时会找到这个文件,然后根据entry找到main.js从而将需要的文件进行打包
//合并完成后,写入到dist目录下的bundle.js文件
- 4、此时我们在控制台输入webpack或者webpack --mode=development命令即可打包,打包后会生成bundle.js压缩文件,这个就是打包后的文件。
- 5、在根目录创建index.html文件,index.html中引入bundle.js资源,即可访问项目所有资源。
- 6、可以直接使用npm run build命令直接打包(不需要4和5步骤)。
案例项目结构如下图:
4、vue-router
vue-router是vue官方指定的路由,通过vue-router可以进行前端项目的页面跳转。
vue-router官方中文文档:https://router.vuejs.org/zh/
vue-router安装:
npm install vue-router@4 #指定版本安装vue-router
npm install vue-router #默认版本安装vue-router
npm uninstall vue-router #卸载vue-router
vue-router实现案例:
- 1、新建组件文件
Hello.vue文件:
<template>
<div>
<h1>Hello World</h1>
</div>
</template>
<script>
export default {
name: 'Hello'
}
</script>
<style scoped>
</style>
main.vue文件:
<template>
<div>
<h1>首页</h1>
</div>
</template>
<script>
export default {
name: 'Main'
}
</script>
<style scoped>
</style>
HelloWorld.vue文件:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<h2>Essential Links</h2>
<ul>
<li>
<a
href="https://vuejs.org"
target="_blank"
>
Core Docs
</a>
</li>
<li>
<a
href="https://forum.vuejs.org"
target="_blank"
>
Forum
</a>
</li>
<li>
<a
href="https://chat.vuejs.org"
target="_blank"
>
Community Chat
</a>
</li>
<li>
<a
href="https://twitter.com/vuejs"
target="_blank"
>
Twitter
</a>
</li>
<br>
<li>
<a
href="http://vuejs-templates.github.io/webpack/"
target="_blank"
>
Docs for This Template
</a>
</li>
</ul>
<h2>Ecosystem</h2>
<ul>
<li>
<a
href="http://router.vuejs.org/"
target="_blank"
>
vue-router
</a>
</li>
<li>
<a
href="http://vuex.vuejs.org/"
target="_blank"
>
vuex
</a>
</li>
<li>
<a
href="http://vue-loader.vuejs.org/"
target="_blank"
>
vue-loader
</a>
</li>
<li>
<a
href="https://github.com/vuejs/awesome-vue"
target="_blank"
>
awesome-vue
</a>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
- 2、工程主入口main.js和App.vue文件
App.vue文件:
<template>
<div id="app">
<img src="./assets/logo.png">
<router-link to="Main">首页</router-link>
<router-link to="Hello">Hello页</router-link>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
main.js文件:
// 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 App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
- 3、添加路由文件index.js
index.js文件:
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '../components/HelloWorld'
import Hello from '../components/Hello'
import Main from '../components/Main'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
component: HelloWorld
},
{
path: '/Hello',
name: 'hello',
component: Hello
},
{
path: '/Main',
name: 'main',
component: Main
}
]
})
项目目录结构:
已验证过通过vue-router实现路由Hello.vue和Main.vue组件
5、Element UI
中文官方文档:https://element.eleme.cn/#/zh-CN/
Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库
Element安装:
npm i element-ui -S #安装element-ui
安装,导入方式使用:
在main.js文件中导入element,后续vue文件就可以使用element UI
//导入element
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css';//使用
Vue.use(Element);
不安装,引用的方式使用:
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
6、vue-axios
中文官方文档:http://axios-js.com/zh-cn/docs/
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。可以整合vue-axios,nuxtjs-axios,react-axios框架。
axios安装
#安装axios
npm install axios
#通过引用的方式使用
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
axios使用
//导入axios
import axios from "axios";
//接口函数传入id,返回的文件流
axios({
method: 'post',
url: 'http://localhost:3144/ctryj/home/getMessage',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
}).then((res)=>{
//接口响应正常处理
}).catch((res)=>{
//接口异常处理
})
封装axios
1、创建request.js文件,内容如下:
/**** request.js ****/
// 导入axios
import axios from 'axios'
axios.defaults.withCredentials = true;
// 使用element-ui Message做消息提醒
import { Message} from 'element-ui';
import { Loading} from 'element-ui';
/**
* 模拟一个出入栈
*/
let loadingInstance = null; // 记录页面中存在的loading
let loadingCount = 0; // 记录当前正在请求的数量
function showLoading(data) {
if (loadingCount === 0) {
loadingInstance = Loading.service({
lock: true,
text: data || '正在加载……'
});
}
loadingCount++
};
function hideLoading() {
loadingCount--
if (loadingInstance && loadingCount === 0) {
loadingInstance.close()
loadingInstance = null
}
}
function getCookie(name) {
let arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
if(arr=document.cookie.match(reg))
return unescape(arr[2]);
else
return null;
}
//1. 创建新的axios实例,
const service = axios.create({
// 公共接口--这里注意后面会讲
baseURL: 'http://localhost:3144/ctryj/',
// 超时时间 单位是ms,这里设置了3s的超时时间
timeout: 20 * 1000
});
// 2.请求拦截器
service.interceptors.request.use(config => {
//使用element-ui做加载
if (!config.loadingHide) {//有的请求隐藏loading
showLoading();
}
//发请求前做的一些处理,数据转化,配置请求头,设置token,设置loading等,根据需求去添加
config.data = JSON.stringify(config.data); //数据转化,也可以使用qs转换
config.headers = {
'Content-Type': 'application/json; charset=utf-8', //配置请求头
};
/*config.responseType = 'blob';*/
//如有需要:注意使用token的时候需要引入cookie方法或者用本地localStorage等方法,推荐js-cookie
/*const token = getCookie("Jsession"); //这里取token之前,你肯定需要先拿到token,存一下
if(token){
config.params = {'token':token} //如果要求携带在参数中
config.headers.token= token; //如果要求携带在请求头中
}*/
return config
}, error => {
Promise.reject(error);
})
// 3.响应拦截器
service.interceptors.response.use(response => {
//接收到响应数据并成功后的一些共有的处理,关闭loading等
hideLoading();
let res = response.data;
// 如果是返回文件
if (response.config.responseType === 'blob') {
return res;
}
// 兼容服务器返回的字符串数据
if (typeof res === 'string') {
res = res?JSON.parse(res) : res
}
return res;
}, error => {
/***** 接收到异常响应的处理开始 *****/
if (error && error.response) {
// 1.公共错误处理
// 2.根据响应码具体处理
switch (error.response.status) {
case 400:
error.message = '错误请求'
break;
case 401:
error.message = '未授权,请重新登录'
break;
case 403:
error.message = '拒绝访问'
break;
case 404:
error.message = '请求错误,未找到该资源'
//window.location.href = "/NotFound"
break;
case 405:
error.message = '请求方法未允许'
break;
case 408:
error.message = '请求超时'
break;
case 500:
error.message = '服务器端出错'
break;
case 501:
error.message = '网络未实现'
break;
case 502:
error.message = '网络错误'
break;
case 503:
error.message = '服务不可用'
break;
case 504:
error.message = '网络超时'
break;
case 505:
error.message = 'http版本不支持该请求'
break;
default:
error.message = `连接错误${error.response.status}`
}
} else {
// 超时处理
if (JSON.stringify(error).includes('timeout')) {
Message.error('服务器响应超时,请刷新当前页')
}
error.message = '连接服务器失败'
}
//关闭加载
hideLoading();
Message.error(error.message)
/***** 处理结束 *****/
//如果不需要错误处理,以上的处理过程都可省略
return Promise.resolve(error.response)
})
//4.导入文件
export default service
2、使用封装组件
import service from "../utils/request"; //引入组件
//方法中使用组件
methods:{
noteList(){
let data = {"userid":"c_liujun"};
service.post("note/queryNoteList",data).then((res)=>{
this.notes = res.data;
})
}
}
7、vue-pdf
概念:vue-pdf是Vue的一个包,它使您能够通过Vue组件轻松地显示和查看pdf。
vue-pdf安装:
npm install vue-pdf #安装VUE-PDF组件
npm install vue-pdf --legacy-peer-deps #如果安装报错,使用该命令
vue-pdf使用:
1、引入插件
import pdf from "vue-pdf"; #引入vue-pdf插件
2、定义组件
export default {
name: "Pdf",
components: {
pdf, #定义pdf组件
},
....
3、使用组件
#使用<pdf>组件
<div class="pdfArea">
# <!-- // 不要改动这里的方法和属性,下次用到复制就直接可以用 -->
<pdf
:src="src"
ref="pdf"
v-show="loadedRatio === 1"
:page="currentPage"
@num-pages="pageCount = $event"
@progress="loadedRatio = $event"
@page-loaded="currentPage = $event"
@loaded="loadPdfHandler"
@link-clicked="currentPage = $event"
style="display: inline-block; width: 100%"
id="pdfID"
></pdf>
</div>
封装pdf-vue插件:
创建Pdf.vue文件,内容如下:
<template>
<div id="container">
<!-- 上一页、下一页 -->
<div class="right-btn">
<!-- 输入页码 -->
<div class="pageNum">
<input
v-model.number="currentPage"
type="number"
class="inputNumber"
@input="inputEvent()"
/>
/ {{ pageCount }}
</div>
<div @click="changePdfPage('first')" class="turn">首页</div>
<!-- 在按钮不符合条件时禁用 -->
<div
@click="changePdfPage('pre')"
class="turn-btn"
:style="currentPage === 1 ? 'cursor: not-allowed;' : ''"
>
上一页
</div>
<div
@click="changePdfPage('next')"
class="turn-btn"
:style="currentPage === pageCount ? 'cursor: not-allowed;' : ''"
>
下一页
</div>
<div @click="changePdfPage('last')" class="turn">尾页</div>
</div>
<div class="pdfArea">
<!-- // 不要改动这里的方法和属性,下次用到复制就直接可以用 -->
<pdf
:src="src"
ref="pdf"
v-show="loadedRatio === 1"
:page="currentPage"
@num-pages="pageCount = $event"
@progress="loadedRatio = $event"
@page-loaded="currentPage = $event"
@loaded="loadPdfHandler"
@link-clicked="currentPage = $event"
style="display: inline-block; width: 100%"
id="pdfID"
></pdf>
</div>
<!-- 加载未完成时,展示进度条组件并计算进度 -->
<div class="progress" v-if="loadedRatio != 1">
<el-progress
type="circle"
:width="70"
color="#53a7ff"
:percentage="Math.floor(loadedRatio * 100) ? Math.floor(loadedRatio * 100) : 0"
></el-progress>
<br />
<!-- 加载提示语 -->
<span>{{ remindShow }}</span>
</div>
</div>
</template>
<script>
import pdf from "vue-pdf";
import service from "../utils/request";
export default {
name: "Pdf",
components: {
pdf,
},
data() {
return {
// ----- loading -----
remindText: {
loading: "加载文件中,文件较大请耐心等待...",
refresh: "若卡住不动,可刷新页面重新加载...",
},
remindShow: "加载文件中,文件较大请耐心等待...",
intervalID: "",
src: "",
data : {
fileId : "",
fileType : "pdf"
},
// 当前页数
currentPage: 0,
// 总页数
pageCount: 0,
// 加载进度
loadedRatio: 0,
};
},
created() {
this.data.fileId = this.$route.query.fileId;
this.data.fileType = this.$route.query.fileType;
this.viewFile(this.data);
},
mounted() {
// // 更改 loading 文字
this.intervalID = setInterval(() => {
this.remindShow === this.remindText.refresh
? (this.remindShow = this.remindText.loading)
: (this.remindShow = this.remindText.refresh);
}, 4000);
},
methods: {
//查看源文件
viewFile(data){
if((data.fileType).indexOf('docx') !== -1){
//Todo:这里代码是docx文件预览,此处省略
}else {
this.loading = this.$loading({
lock: true,
text: "正在加载...",
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.6)'
});
//接口函数传入id,返回的文件流
let config = {responseType: 'blob'};
service.post("home/getPdf", data, config).then((res) => {
let data = res;
let binaryData = [];
binaryData.push(data);
const blob = new Blob(binaryData, {type: 'application/pdf'});
let url = window.URL.createObjectURL(blob);
console.log(url);
if (url != null && url != undefined && url) {
//页面加载,拿到路由中的url复制给data中的src
this.src = url;
this.loading.close()
}
})
}
},
// 页面回到顶部
toTop() {
document.getElementById("container").scrollTop = 0;
},
// 输入页码时校验
inputEvent() {
if (this.currentPage > this.pageCount) {
// 1. 大于max
this.currentPage = this.pageCount;
} else if (this.currentPage < 1) {
// 2. 小于min
this.currentPage = 1;
}
},
// 切换页数
changePdfPage(val) {
if (val === "pre" && this.currentPage > 1) {
// 切换后页面回到顶部
this.currentPage--;
this.toTop();
} else if (val === "next" && this.currentPage < this.pageCount) {
this.currentPage++;
this.toTop();
} else if (val === "first") {
this.currentPage = 1;
this.toTop();
} else if (val === "last" && this.currentPage < this.pageCount) {
this.currentPage = this.pageCount;
this.toTop();
}
},
// pdf加载时
loadPdfHandler(e) {
// 加载的时候先加载第一页
this.currentPage = 1;
},
},
destroyed() {
// 在页面销毁时记得清空 setInterval
clearInterval(this.intervalID);
},
};
</script>
<style scoped>
#container {
background: #f4f7fd;
/*overflow: auto;*/
font-family: PingFang SC;
width: 100%;
display: flex;
justify-content: center;
position: relative;
}
/* 右侧功能按钮区 */
.right-btn {
position: fixed;
right: 5%;
bottom: 15%;
width: 120px;
display: flex;
flex-wrap: wrap;
justify-content: center;
z-index: 99;
}
.pdfArea {
width: 900px;
margin: 0 auto;
}
/* ------------------- 输入页码 ------------------- */
.pageNum {
margin: 10px 0;
font-size: 18px;
}
/*在谷歌下移除input[number]的上下箭头*/
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none !important;
margin: 0;
}
/*在firefox下移除input[number]的上下箭头*/
input[type="number"] {
-moz-appearance: textfield;
}
.inputNumber {
border-radius: 8px;
border: 1px solid #999999;
height: 35px;
font-size: 18px;
width: 60px;
text-align: center;
}
.inputNumber:focus {
border: 1px solid #00aeff;
background-color: rgba(18, 163, 230, 0.096);
outline: none;
transition: 0.2s;
}
/* ------------------- 切换页码 ------------------- */
.turn {
background-color: #164fcc;
opacity: 0.9;
color: #ffffff;
height: 70px;
width: 70px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 5px 0;
}
.turn-btn {
background-color: #164fcc;
opacity: 0.9;
color: #ffffff;
height: 70px;
width: 70px;
border-radius: 50%;
margin: 5px 0;
display: flex;
align-items: center;
justify-content: center;
}
.turn-btn:hover,
.turn:hover {
transition: 0.3s;
opacity: 0.5;
cursor: pointer;
}
/* ------------------- 进度条 ------------------- */
.progress {
position: absolute;
right: 50%;
top: 50%;
text-align: center;
}
.progress > span {
color: #199edb;
font-size: 14px;
}
</style>
使用封装组件:
methods: {
viewFile() {
this.$router.push({
path:'/main/pdf',
//要传的参数
query: {
fileId : this.fileId,
fileType : 'pdf',
}
})
}
}
8、vue-iframe
vue-iframe安装
npm install vue-iframe #安装vue-iframe
npm install vue-iframe --legacy-peer-deps #如果上面安装失败,使用该命令
9、vue-video-player
vue-video-player安装
npm install --save vue-video-player@4.0.6 #安装vue-video-player
npm install --save vue-video-player@4.0.6 --legacy-peer-deps #如果上面安装失败,使用该命令
VUE特殊功能实现
1、控制网页按比例缩放
在vue中控制页面按比例缩放,代码实现如下:
js内容:
export default {
data(){
return{
// 缩放比
screenRatio: Math.round((window.outerWidth / window.innerWidth) * 100),
}
}
watch: {
screenRatio: {
immediate: true, // 开启一直监听
handler: function(val) { // val是获取到的缩放比
if (val < 125) { // 不同缩放比下进行不同的操作
document.querySelector("#content").classList.add("small");
} else {
document.querySelector("#content").classList.remove("small");
}
},
},
},
mounted() {
window.onresize = () => { // 不使用window.onresize只能监听一次,使用可以一直监听
return (() => {
window.screenRatio = Math.round( (window.outerWidth / window.innerWidth) * 100 );
this.screenRatio = window.screenRatio;
})();
};
},
}
css内容:
<style>
.el-icon-body{
margin-top: -15px;
display: flex;
flex-direction: column;
justify-content: center;
width: 96rem;
height: 54rem;
}
.small {
position: absolute;
top:0%;
left: 50%;
transform: translate(-50%, -0%);
}
</style>
html内容:
<template>
<div class="el-icon-body small">
/**
* Todo:页面内容
*/
</div>
</template>
2、通过事件总线,组件A控制组件B页面赋值和刷新
如果A和B组件非父子组件,A与B组件中的通信就需要使用的事件总线。
1、创建event-bus.js文件
import Vue from 'vue';
const EventBus = new Vue();
export default EventBus;
2、在B组件中定义监听事件,
import EventBus from "../../utils/event-bus";
// 在组件B中监听组件A触发的自定义事件 'refresh-video'
mounted() {
EventBus.$on('refresh-video', (url) => {
this.refreshPage(url);
})
},
methods:{
refreshPage(url) {
// 在这里进行组件B的刷新操作
// 例如:重新获取数据、重置状态等
this.playerOptions.sources[0].src=url;
}
}
3、在A组件中设置触发事件
<template>
<div @click="playerVideo"></div>
</template>
<script>
import EventBus from "../../utils/event-bus";
export default {
methods:{
playerVideo(){
// 触发自定义事件 'refresh-video'
EventBus.$emit('refresh-video',
"https://stream7.iqilu.com/10339/upload_transcode/202002/18/20200218114723HDu3hhxqIT.mp4");
}
}
}
</script>