1、vue知识点的综合使用:不能把所学的vue知识点串起来
2、vue项目的创建流程:
(1)vue init webpack 项目名称 -- vue-cli + webpack
(2)webStorm创建vue项目:
A、简洁方式创建:基本的vue项目结构
B、带有语法检查、测试模块的项目:自带有ESLint模块、vue.config.js文件(vue项目的配置文件--如配置vue2项目的默认端
口号)
3、组件的创建
(1)组件:是一个html、css、js的封装体,可以复用。是vue的核心之一。
面试问题:组件的data为什么必须是函数
(2)组件的通信:
A、组件之间的关系:父子关系(props、$emit)、兄弟关系(mitt、vuex)、跨级关系(vuex、provider/inject)
(3)组件的插槽:扩展组件的功能
(4)组件的注册:通过components进行注册
4、vue-router:路由模块
(1)路由:当用户单击某个超链接时,将对应组件渲染出来的过程称为路由
(2)路由配置文件:
A、 创建全局的VueRouter对象(路由器):定义路由表(跳转路径和组件之间的映射关系)、路由模式(hash、history)
B、路由表:是一个数组,包含了若干条路由信息
路由信息:path(路由路径)、component(路由路径对应的组件)、name(路由路径的别名)、
children(配置子路由)
特殊的路由路径:/(项目的根路径)
/*:表示匹配所有路径,通常放在路由路径的末尾(如404页面)
C、三大组成部分:
A、< router-link to="url">:超链接组件,作用类似a标签
B、< router-view> :路由视图,组件渲染的出口
C、VueRouter
(3)在全局的Vue实例中注册路由器
5、axios模块:异步请求模块,封装了ajax
(1)什么是ajax:异步的javascript和xml
(2)同步和异步
(3)回调函数:
(4)数据封装:将服务器端响应的数据统一封装在响应对象的data属性中
(5)请求对象(request)--- 简写为req,客户端向服务器发起的请求(请求头信息、请求数据等)都封装在该对象中
在服务器端通过request对象来获取客户端数据时,都要使用该对象
(6)响应对象(response)--- 简写res,通过该对象将服务器端处理后的数据响应给客户端
(7)axios拦截器:
A、请求拦截器:对客户端的请求进行过滤
B、响应拦截器:对服务器端的响应信息进行拦截,简化前端页面对服务器端响应数据的处理
二、示例:
1、技术点:vue2.6 、 element-ui 、 axios 、 vue-router 、 vuex 、mockjs 、数据可视化(Echarts、antv)
2、突出vue2技术:不写node后台,使用mockjs模拟后台数据、后台接口
3、安装相关的技术模块
(1)安装mockjs:npm i mockjs
(2)安装element-ui:npm i element-ui
(3)安装axios:npm i axios
(4)安装vue-router:npm i vue-router@3
(5)安装vuex:npm i vuex@3
4、定义mockjs的配置文件:生成后台的模拟数据、接口
(1) src / mock / mock.js
import Mock from "mockjs"
const Random=Mock.Random
const data=[]
//调用Mock.mock方法生成随机数据
Mock.mock(()=>{
for (let i =0;i<10;i++ ){
//利用mockjs的Random随机生成数字并转化为十六进制,拼接
const a="#"+Random.integer(180,255).toString(16)+
Random.integer(180,255).toString(16)+
Random.integer(120,220).toString(16)
let t =null //用来存放Random随机生成的用户名
let male=["男","女"] // 用来存放性别信息的数组
data.push({
"userId":1001+i,
userName:t=Random.cname(), //随机生成中文名字
userMale:male[Random.integer(0,1)], //在下标,随机生成0或1,就可以随机获取性别
headImage:Random.image("140x140",a,t),//第一个参数图片的大小,第二个参数颜色,第三个参数是图片上显示的文本
userBirthday:Random.datetime('yyyy-MM-dd HH:mm:ss'),//生成随机日期,yyyy格式
userAddress:Random.county(true) //省市县区随机地址
})
}
})
//查询所有-接口 (模拟后台接口)
Mock.mock("/api/find","get",data)//第一个参数,接口地址 。第二个参数:请求方式,第三个参数:响应数据
//在main.js中去导入,将mockjs文件在项目中共享,项目中的所有组件都可以访问接口
(2)在项目的main.js中导入mockjs的配置文件:将mockjs文件在项目中共享,项目中的所有组件都可以访问mockjs提供的数据和接口
import './mock' //默认导入的是mock目录下的index.js文件
如果不是,则要写全部地址 import "./mock/mock" //导入mock
使用axios模块:不做全局配置(即哪个组件使用axios就在组件中引用即可)
6、使用vuex进行全局的数据处理
(1)创建vuex的配置文件:/src/store/index.js
(2)在项目的main.js文件中注册store对象
import store from "./stroe/index";
new Vue({
store,
router,
render: function (h) { return h(App) },
}).$mount('#app')
7、在组件中使用vuex
8、使用element-ui组件库
(1)在项目的main.js导入element-ui、导入element-ui的样式文件
import ElementUI from "element-ui" //导入element-ui库
import "element-ui/lib/theme-chalk/index.css" //导入element-ui的样式文件
Vue.use(ElementUI)
(2)el-table的基本用法
A、给el-table的data属性绑定变量:该变量是一个数组或集合,即在表格中展示的数据
B、el-table的事件:
a、select:当用户手动勾选数据行的 Checkbox 时触发的事件,默认参数是selection, row
参数selection:是用户选择的数据,是数组类型,即用户选择了几行,selection数组就有几个单元
参数row:用户选择的当前行
b、select-all:当用户手动勾选全选的 Checkbox 时触发的事件,默认参数是selection
参数selection:是一个数组,存放的全选的所有数据
c、selection-change:当选择项发生变化时会触发该事件,默认参数是selection
(3)在组件中加入分页
强调的问题:
A、表格(el-table)的样式问题:如A组件是父组件,B组件是子组件,在B组件中使用el-table,出现表格的表头高度不受控制的情况(在B组件中设置表头的高度无效),原因是样式污染即在A组件的样式中有height属性的设置,它污染了B组件中的el-table
B、表格中数据的获取途径:
组件(el-table) —->向vuex的actions派发动作 —-> 在actions的函数中向后台接口发起异步的请求—->actions向mutations提交
修改state的请求同时将从服务器端获取的数据传递过去 —-> 修改state属性的值(即将服务器端的响应数据赋给state属性) —-> 在组件中
通过vuex的getters获取state中的数据并渲染到el-table中
C、分页思想
a、数据总量:数据的记录总数
b、每页显示的记录数
c、总页数
d、分页实现方法:
总记录数:20 —-> arr
每页显示的记录数:5 —->pageCount
页数:4 —->pagesize
1 2 3 4 —->currentPage
每页第一个数据在数组中的下标:start = (currentPage - 1) * pageCount
取分页数据:arr.splice(start,pageCount)
(4)路由问题
A、< router-link to=”url”>链接文本 | 图像 | 视频< /router-link > //封装了a标签
B、< router-view></ router-view>:路由视图 (路由出口)
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter({
routers:[
{
path:'/home',
name: 'home',
component: ()=>import Home from './componets/Home'
}
],
mode: 'history'
})
export default router
在main.js中注册路由器
import Vue from 'vue'
import App from './App.vue'
import store from "./store/index"
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import './mock'
import router from './router/index'
Vue.use(ElementUI) //在Vue实例中注册element-ui
new Vue({
store,
router,
render: h => h(App),
}).$mount(
在组件中使用(App.vue)
<router-view name="命名视图"></router-view>
Son.vue
<router-link :to="{name:'home'}">首页</router-link>
(5)axios的拦截器
A、响应拦截器:对服务器的响应数据进行过滤,使前端能够更简单的使用这些数据
B、请求拦截器:对客户端的请求进行拦截,保证只有合法的请求才能进入服务器
import axios from 'axios'
const $http = axios.create({
baseURL: 'http://localhost:8089',
timeout: 2000
})
async $http.getAll(url,params){
return await this.get(url,params)
}
export default $http
(6)数据可视化
A、Echarts
a、安装:npm i echarts@4.9.0
b、在main.js中配置:
import * as echarts from ‘echarts’
Vue.prototype.echarts = echarts
c、在vue组件的虚拟DOM中定义echarts的挂载点
d、对echarts的各个配置项进行配置(以柱状图bar为例)
title:图表的标题
tooltip:鼠标悬浮在图表上时显示的提示信息
xAxis:x轴的文本
yAxis:y轴的文本
series:是一个数组,包含多个对象,一个对象就是图表中一组柱子
type:表示的图表的类型(bar表示柱状态图、line表示折线图、pie表示饼图……)
data:是一个数组,有多少个单元就显示多少个柱子
B、vue-echarts模块的使用
a、安装:npm i vue-echarts
b、导入:
import 'echarts'
import VueECharts from "vue-echarts";
import "echarts/lib/chart/bar";
c、在vue组件中注册vue-echarts
export default {
name: 'App',
components: {
'v-chart':VueECharts
}
}
d、在vue组件的data函数中定义vue-echarts配置项
data: function () {
return {
bar: {
color: ["#ffdd38", "#0fc7ab"], // 柱状图颜色设置
title: {
text: "Vue-ECharts 入门示例",
left: 'center' //标题居中
},
tooltip: {},
animation: false, //不显示动画效果
legend: { //图例设置
//show: false, //是否显示图例
icon: "circle", // 将图例设置成原型
bottom: 0, //图例显示的位置
left: "center",
itemWidth: 10,
itemHeight: 10,
},
xAxis: { //x轴显示的内容
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"],
axisLabel: {
rotate: -30 //显示内容的倾斜度
}
},
yAxis: [
{
type: 'value',
name: '销量',
min: 0, //设置y轴刻度的最小值
max: 40, //设置y轴刻度的最大值
interval: 5, //y轴的间隔数
axisLabel: { //y轴标签的显示格式
formatter: '{value}件'
},
splitLine: { //y轴分隔线
show: true, //显示分隔线
lineStyle: {
type: "dashed", //线型
color: 'red' //线条颜色
}
},
axisLine: {
show: true, //是否显示坐标轴轴线
},
axisTick: {
show: false, //去掉y轴刻度线
}
}
],
series: [
{
name: "实体店",
type: "bar",
data: [5,20,36,10,10,20]
},
{
name: "网店",
type: "bar",
data: [15,30,39,18,22,35]
}
]
}
}
}
}
e、在vue组件的DOM中应用
<v-chart :options="bar"></v-chart>
实现购物车的功能
(1)数据来源:商品信息保存在goods.js文件中。(商品信息:编号、名称、单价)
(2)使用element-ui的el-table显示所有商品信息
(3)在el-table中增加’购买数量’和’操作’两列
a、’购买数量’:可以实现购买数量的增加和减少,数量最低值必须是1
b、’操作’:有“删除”按钮,可以删除所在行的商品
(4)根据用户对商品的选择和购买数量,显示总价
二、MVVM架构:Model — View — ViewModel
1、数据的双向绑定:Model ——> View View ——>Model
2、vue中MVVM的体现:
Model(数据模型):是存放数据的。组件或vue实例的data。
View(视图模型):是渲染数据的。组件中的DOM部分(template中的内容)
ViewModel(视图-模型):实现了Model和View之间的绑定。vue实例就是ViewModel
三、vue中computed计算属性和methods的区别
1、methods方式:
控制台输出:
当修改其中一个属性时,其他属性的值都没改变,但会发现method里的方法都被执行
2、computed方式
控制台输出:
会发现当修改其中一个值得时候,只会执行与其相关的方法
3、总结
(1)methods和computed,两种方式的最终结果完全相同
(2)不同的是计算属性是基于它们的响应式依赖进行缓存的
只有相关响应式依赖发生改变时它们才会重新求值,多次访问getAge会立即返回之前的计算结果,而不必再次执行函数。
(3)methods方法,每当触发重新渲染时,调用方法将总会再次执行函数
建议:对于任何复杂逻辑,都应当优先使用计算属性
三、vue的响应式原理是什么?
1、vue响应式的基本原理:
(1)通过Object.defineProperty来实现监听数据的改变和读取(属性中的getter和setter方法) 实现数据劫持
(2)观察者模式(发布者-订阅者模式)
观察者(订阅者) – Watcher:
update():当事件发生时,具体要做的事情
目标(发布者) – Dep:
①subs 数组:存储所有的观察者
②addSub():添加观察者
③notify():当事件发生,调用所有观察者的 update() 方法
(3)数据发生改变通过发布者订阅者模式来进行通知 进行界面刷新
2、响应过程
(1)首先要对数据(data)进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发生变化了,就需
要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器(发布者)Dep来专门收集这些订阅
者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。
(2)接着还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并
替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。
Vue实例中的data中的每个属性都会被创建一个Dep(发布者)对象,且解析el时进行视图的初始化如果html中有多个地方用到该属性,
则每个地方都会生成一个Watcher(订阅者)的实例被放入到该属性对应Dep(发布者)的实例中的subs数组中。当属性发生改变
时,Observe监听到属性的改变,然后调用该属性对应的Dep(发布者)实例的notify方法,然后notify方法会对Dep(发布者)实例中的
数组进行遍历然后同时调用遍历出的Watcher(订阅者)的实例进行update方法的调用进行视图的更新。伪代码如下:
const obj = {a:15}
Object.keys(obj).forEach(key => {
let value = obj[key]
Object.defineProperty(obj, key, {
get() {
console.log('试图读取obj的a属性')
},
set(newValue) {
console.log('试图改变obj的a属性')
//属性变化时进行对Watcher实例进行通知
dep.notify()
}
})
})
//发布者
class Dep{
constructor(){
this.subs = []
}
addSub(watch){
this.subs.push(watch)
}
//属性变化发送通知函数
notify(){
//接受到通知后 调用update函数进行视图的更新
this.subs.forEach(item => {
item.update()
})
}
}
//订阅者
class Watcher {
constructor(name){
this.name =name
}
update(){
console.log(this.name+'发生update');
}
}
//模拟创建一个发布者
const dep = new Dep()
//模拟创建一个订阅者
const w1 = new Watcher('第一个实例')
//将订阅者添加到发布者中subs的数组里进行管理
dep.addSub(w1)
const w2 = new Watcher('第二个实例')
dep.addSub(w2)
const w3 = new Watcher('第三个实例')
dep.addSub(w3)
(3)因此我们可以执行以下3个步骤,实现数据的双向绑定:
A、实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
B、实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
C、实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
四、 AntV数据可视化
1、简介: AntV 是一套专业的数据可视化规范,这套规范的目的是为了让可视化的使用者更懂数据可视化。这套规范是蚂蚁金服在可
视化建设过程中的理论沉淀,它可以很好得指引产品经理,设计师和工程师怎样正确得使用可视化及可视化技术,规避常见的错误。
2、全局使用方法
(1)安装antv/g2
yarn add @antv/g2 --save
或
npm install @antv/g2 --save
(2)全局使用(在main.js中挂在到vue原型实例中)
const G2 = require('@antv/g2')
Vue.prototype.$G2 = G2
(3)vue组件中能够直接在mounted生命周期中直接使用
<template>
<div id="c1"></div>
</template>
<script>
export default {
name: "AntV",
data(){
return {
msg: "",
chart: null,
data: [
{ genre: "运动", sold: 275 },
{ genre: "行动", sold: 115 },
{ genre: "动作", sold: 120 },
{ genre: "设计", sold: 350 },
{ genre: "其他", sold: 150 }
]
}
},
methods:{
initComponent() {
const chart = new this.$G2.Chart({
container: "c1",
width: 600,
height: 300
});
chart.source(this.data);
chart
.interval()
.position("genre*sold")
.color("genre");
this.chart = chart;
this.chart.render();
}
},
mounted() {
this.initComponent()
}
}
</script>
3、按需使用方法
(1)安装antv/g2
yarn add @antv/g2 --save
或
npm install @antv/g2 --save
(2)在组件中按需引入
<template>
<div>
<div id="l1"></div>
</div>
</template>
<script>
import { Chart } from "@antv/g2";
export default {
name: "AntV2",
data() {
return {
year: [
{ year: "1991", value: 3 },
{ year: "1992", value: 4 },
{ year: "1993", value: 3.5 },
{ year: "1994", value: 5 },
{ year: "1995", value: 4.9 },
{ year: "1996", value: 6 },
{ year: "1997", value: 7 },
{ year: "1998", value: 9 },
{ year: "1999", value: 13 }
]
};
},
methods: {
initLineChart() {
const chart = new Chart({
container: "l1",
autoFit: true,
height: 500
});
chart.data(this.year);
chart.scale({
year: {
range: [0, 1]
},
value: {
min: 0,
nice: true
}
});
chart.tooltip({
showCrosshairs: true, // 展现 Tooltip 辅助线
shared: true
});
chart
.line()
.position("year*value")
.label("value");
chart.point().position("year*value");
chart.render();
}
},
mounted() {
this.initLineChart()
}
}
</script>
4、水平柱状图
(1)安装:npm i @antv/g2plot
(2)在组件中引入:import { Bar } from “@antv/g2plot”
(3)创建图表对象:
<template>
<div>
<div id="l2"></div>
</div>
</template>
<script>
import { Bar } from "@antv/g2plot"
export default {
name: "AntV2",
data() {
return {
years: [
{ year: "1991", value: 3 },
{ year: "1992", value: 4 },
{ year: "1993", value: 3.5 },
{ year: "1994", value: 5 },
{ year: "1995", value: 4.9 },
{ year: "1996", value: 6 },
{ year: "1997", value: 7 },
{ year: "1998", value: 9 },
{ year: "1999", value: 13 }
]
};
},
methods: {
initBar(){
const bar = new Bar('l2', {
data:this.years,
xField: 'value',
yField: 'year',
seriesField: 'year',
legend: {
position: 'top-left',
}
});
bar.render();
}
},
mounted() {
this.initBar()
}
}
</script>