这里写目录标题
- VUE
- 1.Vue是什么?
- 优点
- 缺点
- 2.app.vue
- 3.ajax
- 4.取dom元素
- 5.轮播图 element-ui
- 6.mock
- 7.vue-lazyload
- 8.插槽([用法](https://juejin.im/post/5d5b9b2fe51d4561f64a080c),[原理](https://juejin.im/post/5d676f97e51d4561ce5a1c85))
- 9.缓存页面([keep-alive的魔法上](https://juejin.im/post/5d8871c851882509630338c4)[keep-alive的魔法下](https://juejin.im/post/5da42574f265da5b991d6173))
- 10.事件修饰符([传送门](https://juejin.im/post/5bdab661e51d451d804c8933))
- 11.按键修饰符
- 12.表单修饰符
- ES6
- ES6扩展
- Webpack
- Babel
- Promise/Aysnc
- Vue一些对比
- Vue组件
- Vue路由
- Vue动画
- Vue钩子
- Vux
VUE
1.Vue是什么?
- Vue是一个渐进式的javaScript开发框架,通过组建的开发,最后合并组件形成页面。
- 构造器(构造函数)
- 自动化构建工具
优点
- 组建化开发
- 单页面路由
- 丰富的Api方法
- 双向的数据绑定
- 单向数据流
- 易于结合其他第三方库
缺点
- 生态系统不够完善
- 可扩展性稍差
1、全局安装 npm install -g vue-cli
2、创建项目 vue init webpack my-project
3、安装依赖包 npm install
下包:
cnpm i --save-dev vue
CDN:内容分发网络/智能虚拟网络
v-on:click 缩写 @click
v-on:click="alert($event)" // 阻止默认行为
v-on:click.prevent="alert" // 利用修饰符阻止默认行为
指令
v-show
v-html
v-text
v-bind:src="list.img" // 绑定属性 所有属性都可以
v-for="list in lists" // 循环
插值
{{message}}
v-html="message" // 可以解析html元素
v-text="message" // 只能解析字符串
<div id="app">
{{message}}
{{message+""}} // 表达式
<input type="text" v-model="message">
<button v-on:click="alert">点击</button>
</div>
let vm = new Vue({
el:"#app", // 挂载对象
data:{ // 实例属性 // data是一个方法返回一个对象
message:"世界您好!"
},
beforeCreate(){ // 创建
// 挂载元素 实例属性 实例方法 都没有生成
},
created(){ // 创建完成
// 挂载元素 还是没有被初始化
// 实例属性 实例方法 编译出来
},
beforeMount(){
// 挂载元素 初始化了,但是模板还没有被编译,原样输出
// 实例属性 实例方法 编译出来
},
mounted(){
// 挂载元素 初始化 模板被编译
// 属性 初始化
// 方法初始化
},
beforeUpdate(){
// 数据更新前
},
updated(){
// 数据更新后
// 当数据发生改变都会被updated捕获到
}
methods:{ // 方法
alert(e){
// e.preventDefault();
alert(this.message)
}
}
})
2.app.vue
自动添加前缀
postcss-loader
autoprefixer
sass-loader
{
loader:'postcss-loader',
optiond:{
sourceMap:true,
config:{
}
}
}
vue init webpack-simple aaa
vue
vue-loader
vue-template-compiler
vue-style-loader
<template>
<div>
<h1 v-bind:style="{fontSize:'12px'}">绑定样式</h1> // 直接赋值形式
<h2 v-bind:style="styleObj">绑定样式</h2> // 对象形式
<h3 v-bind:style="[obj1,obj2]">绑定样式</h3> // 数组形式
<p v-bind:class="['text-res':true]">绑定类</p> // 数组形式
</div>
</template>
<script>
export default:{
name:'app',
data(){
return{
styleObj:{
fontSize:"20px",
color:"red"
},
obj1:{
color:"#dec"
},
obj2:{
color:"green"
}
}
},
computed:{
// computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter
sum(){
return Number(this.vall)+Number(this.val2)
}
},
watch:{ // 监听新值和旧值
slogin(){
}
}
}
</script>
<style scoped> // 只在当前作用域里生效
.text-red{
color:red;
}
</style>
3.ajax
axios
4.取dom元素
ref="aaa" this.$refs.aaa
5.轮播图 element-ui
main.js
import Element from 'element-ui'
Vue.use(Element)
页面
<el-carousel :interval="3000">
<el-carousel-item v-for="(list,ind) in Imgs" :key="ind">
<img :src="list.picUrl" class="img_res">
</el-carousel-item>
</el-carousel>
style
@import url('element-ui/lib/theme-chalk/index.css');
6.mock
下包:
mock-axios-adapter
import mockjs from 'mockjs';
import axios from 'axios';
import axiosAdapter from 'mock-axios-adapter' // 拦截axios请求
const mock = new axiosAdapter(axios);
mock.onGet('地址').reply(200,{
errCode:0,
errMsg:'',
result:[{
url:'./static/img/banner.jpg'
}]
})
7.vue-lazyload
1、安装插件
npm install vue-lazyload --save-dev
2. main.js引入插件:
import VueLazyLoad from 'vue-lazyload'
Vue.use(VueLazyLoad,{
error:'./static/error.png',
loading:'./static/loading.png'
})
3. vue文件中将需要懒加载的图片绑定 v-bind:src 修改为 v-lazy
<img class="item-pic" v-lazy="newItem.picUrl"/>
8.插槽(用法,原理)
<slot></slot>
两端对齐:
vertival-align:sub
9.缓存页面(keep-alive的魔法上keep-alive的魔法下)
用这个标签包裹起来
<keep-alive>
<router-view/>
</keep-alive>
10.事件修饰符(传送门)
.stop .prevent .capture .self .once
<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>
<!-- click 事件只能点击一次,2.1.4版本新增 -->
<a v-on:click.once="doThis"></a>
11.按键修饰符
// 为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter // 回车键抬起
.tab // tab切换键抬起
.delete (捕获“删除”和“退格”键)
.esc //退出键抬起
.space // 空格键抬起
.up // 上
.down // 下
.left // 左
.right // 右
.对应键盘码 // 使用键盘码是要注意如果不是以上对应的键盘修饰符,需要创建按键修饰符
使用方式:
<p @keyup.enter="add"></p> // @click.按键修饰符
<p @keyup.13="add"></p> // @click.对应键盘码
12.表单修饰符
- .lazy
.lazy 在默认情况下,v-model在每次input事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加lazy修饰符,从而转变为使用change事件进行同步:
<!-- 在"change"时而非"input"时更新 光标移除input输入框的时候 -->
<input type="text" v-model:value.lazy="message">
<input v-model.lazy="message" >
new Vue({
el: '#app',
data: {
message: ''
}
})
- .number
.number 如果想自动将用户的输入值转为数值类型,可以给v-model添加number修饰符
<input v-model.number="age" type="number">
这通常很有用,因为即使在type="number"时,HTML输入元素的值也总会返回字符串。如果这个值无法被parseFloat()解析,则会返回原始的值。
- .trim
.trim 如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符
<input v-model.trim="msg">
ES6
1、变量声明
// es5
声明变量 var --- variable
用大写的形式去声明常量:var PI = 3.14159255358;
常量的值允许被修改
// es6
// 通过let 关键字代替 var 来声明变量,用发与var几乎一致
当let/const遇到{}会形成这个变量的块级作用域
声明变量 let --- 叫命令或关键字
声明常量 const PI = 3.1415926;
报错会阻断下面的代码执行
报错:Assignment to constant variale
常量的值不允许被修改
// 变量、常量不得重复定义(相同作用域)
报错:Identifier 'num' has already been declared
2、变量提升
- es5
var 存在变量提升,只要在声明之前调用,就会有变量提升,并且值为undefined
- es6
let 语句声明的参数没有变量提升
暂时性死区的概念:在变量声明之前调用,都是该变量的暂时性死区
3、结构赋值
- 三种状态
- 模式不匹配
- 结构不成功:声明了变量,没有复制( undefined )
- 不完全结构
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称作解构赋值
// 数组的解构赋值
// es5
var a = 1;
var b = 2;
var c = 3;
// es6 好处:代码简洁
// 数组
let [a,b,c] = [1,2,3];
console.log(a);
console.log(b);
console.log(c);
// 对象
let person = {
name: 'zs',
age: 18,
hoppy: ['吃饭', '睡觉', '打豆豆'],
address: '北京八维'
}
let { obj: objs, obj: obj1 } = {
obj: person
}
console.log(objs)
// 字符串
// 会将字符串转换成类似数组的一个对象
let [a,b,c] = 'mmd';
// a = m
// b = m
// c = d
let {length:len} = 'mmd';
// len = 3
// 数组的解构赋值在函数中应用
let fun = function([name,age]){ // 接收的是形参
console.log(name);
console.log(age);
}
fun(['zs',18]) // 传递的参数是实参
// 对象的解构赋值在函数中应用
let fun = function({name,age}){ // 接收的是形参
console.log(name);
console.log(age);
}
fun({name:'zs',age:18}) // 传递的参数是实参
// 通过数组的解构赋值,返回一个值
let fun = (val) => {
return [val, val + "you aer the best!"];
}
console.log(fun())
// 通过对象的解构赋值来取json数据
const data = {
name:'zs',
age:18
}
let {name,age} = data;
console.log(name);
console.log(age)
总结
- 结构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。
- 由于 undefined 和 null 无法转为对象,所以对他们进行结构赋值都会报错。
4、语法提案的批准流程传送门
-
Stage 0 - Strawman(展示阶段)
Stage 0 “稻草人” —— 这是所有提案的起点。在进入下一阶段之前,提案的内容可能会发生重大变化。目前还没有提案的接收标准,任何人都可以为这一阶段提交新的提案。无需任何代码实现,规范也无需合乎标准。这个阶段的目的是开始针对该功能特性的讨论。目前已经有超过 20 个处于 stage 0 的提案。
-
Stage 1 - proposal(征求意见阶段)
Stage 1 “提案” —— 一个真正的正式提案。此阶段的提案需要一个“拥护者”(即 TC39 委员会的成员)。此阶段需仔细考虑 API 并描述出任何潜在的、代码实现方面的挑战。此阶段也需开发 polyfill 并产出 demo。在这一阶段之后提案可能会发生重大变化,因此需小心使用。目前仍处于这一阶段的提案包括了已望穿秋水的 Observables type 与 Promise.try 功能。
-
Stage 2 - Draft(草案阶段)
Stage 2 “草案” —— 此阶段将使用正式的 TC39 规范语言来精确描述语法。在此阶段后仍由可能发生一些小修改,但是规范应该足够完整,无需进行重大修订。如果一个提案走到了这一步,那么很有可能委员会是希望最终可以实现该功能的。
-
Stage 3 - Candidate(候选人阶段)
“候选” —— 该提案已获批准,仅当执行作者提出要求时才会做进一步的修改。此时你可以期待 JavaScript 引擎中开始实现提案的功能了。在这一阶段草案的 polyfill 可以安全无忧使用。
-
Stage 4 - Finished(定案阶段)
Stage 4 “完成” —— 说明提案已被采纳,提案规范将与 JavaScript 规范合并。预计不会再发生变化。JavaScript 引擎将发布它们的实现。截至 2017 年 10 月,已经有 9 个已完成的提案,其中最引人关注的是 async functions。
5、字符串扩展
1、String.includes(string) 用来判断字符串中是否包含指定参数(string)
2、String.startsWith(string) 字符串是否以XX开始
3、String.endsWith(string) 字符串是否以XX开始
string.includes(string,start)
string 代表查询参数
start 代表查询起始位置
includes() 具备隐式转换
let str = '123木头人'
console.log(str.includes('123',3)) // 结果为false
// str.repeat() ''
// str.repeat(0) ''
// str.repeat(1) mmd
// str.repeat(2) mmdmmd
let str = 'mmd';
let newString = str.repeat();
console.log(newString)
let str = 'mmd';
console.log(str.padStart(5,'*')) // **mmd
console.log(str.padEnd(5,'*')) // mmd**
ES6扩展
方法 | 说明 |
---|---|
Number.isFinite() | 判断一个值是不是有限的 |
Number.isNaN() | 判断一个值是不是NaN |
Number() | 类型转换 |
Number.parseFloat() | 将字符串转换为小数 |
Number.parseInt() | 将字符串转换为整数 |
Number.isInteger() | 判断一个数是不是整数 |
Number.isSafeInteger() | 判断是不是一个完全的数 |
Math.cbrt() | 用于计算一个数的立方根 |
Math.trunc() | 用于去除一个数的小数部分,返回整数 |
1、如果参数类型不是数值,Number.isFinite一律返回false
2、如果参数类型不是NaN,Number.isNaN一律返回false
注:es5含有隐式转换,es6不含有隐式转换
// es5
isFinite(25) // true
isFinite("25") // true
// es6
Number.isFinite(25) // true
Number.isFinite("25") // false
// es5
isNaN(NaN) // true
isNaN("NaN") // true
// es6
Number.isNaN(NaN) // true
Number.isNaN("NaN") // false
Number.isNaN(1) // false
3、Number.parseInt(), Number.parseFloat()
// ES5的写法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
4、Number.isInteger()用来判断一个数值是否为整数
Number.isInteger(25) // true
Number.isInteger(25.1) // false
Number.isInteger(25.0) // true
// 如果参数不是数值,Number.isInteger返回false
Number.isInteger() // false
Number.isInteger(null) // false
Number.isInteger('15') // false
Number.isInteger(true) // false
5、Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内
Number.isSafeInteger('a') // false
Number.isSafeInteger(null) // false
Number.isSafeInteger(NaN) // false
Number.isSafeInteger(Infinity) // false
Number.isSafeInteger(-Infinity) // false
Number.isSafeInteger(3) // true
Number.isSafeInteger(1.2) // false
Number.isSafeInteger(9007199254740990) // true
Number.isSafeInteger(9007199254740992) // false
Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1) // false
Number.isSafeInteger(Number.MIN_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false
6、Math.trunc方法用于去除一个数的小数部分,返回整数部分
Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
Math.trunc(-4.9) // -4
Math.trunc(-0.1234) // -0
// 对于非数值,Math.trunc内部使用Number方法将其先转为数值
Math.trunc('123.456') // 123
Math.trunc(true) //1
Math.trunc(false) // 0
Math.trunc(null) // 0
// 对于空值和无法截取整数的值,返回NaN
Math.trunc(NaN); // NaN
Math.trunc('foo'); // NaN
Math.trunc(); // NaN
Math.trunc(undefined) // NaN
7、Math.cbrt方法用于计算一个数的立方根
Math.cbrt(-1) // -1
Math.cbrt(0) // 0
Math.cbrt(1) // 1
Math.cbrt(2) // 1.2599210498948734
对于非数值,Math.cbrt方法内部也是先使用Number方法将其转为数值
Math.cbrt('8') // 2
Math.cbrt('hello') // NaN
1、设置默认值
- 回调里面使用箭头函数,this指向上级对象
- 回调里面使用function,this指向当前对象
// es5
let fun = function(val){
var val = val || 666;
return val
}
console.log(fun())
// es6
let fun = (val=666) => {
return val;
}
// 简写
let fun = (val=666) => val;
// 函数默认值的注意事项
// 定义形参默认值,需要注意:先声明后使用,遵循声明变量的规则
let fun = (val,val) => { // 报错
console.log(val)
}
let fun = (val2 = 2,val1 = val2) => {
console.log(val1)
}
fun();
// 设置形参后,函数内部的私有变量如果用let命令来声明变量,不得重复定义
let fun = (val) => { // 报错
let val = 666;
console.log(val)
}
fun(555);
// 获取函数所有形参
// es5
let fun = function(){
console.log(arguments); // 类数组
[...arguments].forEach(item=>{ // 通过...把它转为一个数组
console.log(item);
})
}
fun(1,2,3,4,5)
// es6
// 箭头函数没有arguments对象
// reset 参数返回一个实参的数组的集合
let fun = (...reset) => {
console.log(reset)
reset.forEach(item=>{
console.log(item);
})
}
fun(1,2,3,4,5,6)
2、扩展运算符…
- 可扩展一个数组
3、伪逗号
- es2017允许你去写一个逗号
let obj = {
name:'zs',
age:18,
}
4、数组的扩展
1、扩展运算符
// 将数组转化为数组项的参数系列
let arr1 = [1,2,3,4];
let arr2 = [...arr1];
2. Array.from(arr)
// 将类似数组、可以遍历对象(包括set map解构类型的数据) 转为数组
...arr 展开数组的每一项 [...arr] 转为一个数组
3、数组的空值/空位
let arr = new Array(5);
// 长度为5 a[0]为undefined
4、Array.of() 用来将一组参数序列转为数组,可以用来代替new Array()
let arr = Array.of(1,2,3,4,5);
console.log(arr)
// 不传参为空数组
5、Array.copyWithin(target,start,end)
用数组中的一些项,替换数组中的值
// target(必须): 要替换项的下标
// start(可选): 替换的起始下标
// end(可选): 替换的结束下标
let arr = [1, 4, 2, 5, 3, 2];
console.log(arr.copyWithin(0, 4))
// [ 3, 2, 2, 5, 3, 2 ]
6、Array.find() 返回满足条件的第一个项
let arr = [2,8,4,3];
let res = arr.find((item,index,array)=>{
return item>2;
})
console.log(res) // 8
7、Array.findIndex() 返回满足条件的第一个项下标
let arr = [2,8,4,3];
let res = arr.findIndex((item,index,array)=>{
return item==2;
})
console.log(res) // 0
8、Array.fill() 给数组填充相同的值
let arr = new Array(5);
arr.fill("mmd",2,3)
// 2 是开始下标
// 3 是结束下标
9、去重 结合set实现数组去重
let arr = [1,2,3,4,5,2,1,3,4,4];
let res = new Set(arr);
console.log(res) // 转为一个类数组
let result = Array.from(res); // 转数组
5、this指向
构造器 === 构造函数
1、箭头函数不是一个构造器,不可以实例化
let fun = () => {
}
new fun() // 报错
2、:: 左边是一个对象 右边是一个方法
Webpack
1、简介
- 模块的打包器(讲多个文件打包为一个文件夹)
- 自动化构建工具(和gulp类似)
- 在webpack当中任何一个文件都需要一个loader解析文件
2、能干啥?
- 提升网站的响应速度,减少http请求数
3、开始
cnpm install -g webpack
cnpm install -g webpack-cli
配置文件
默认:webpack.config.js
下包:
extract-text-webpack-plugin@next // 样式的抽离
const path = require('path');
const htmlwebpackplugin = require('html-webpack-plugin'); // 新建html页面
// 将多个样式表打包为一个样式表
const ExtractTexPlugin = require('extract-text-webpack-plugin') // 样式的抽离
function entries(){
let temp = {};
let pathname = path.join(__dirname,'src');
let files = fs.readdirSync(pathname);
files.map(file =>{
let pathUrl = path.join(pathname,file);
ley stats = fs.statSync(pathUrl);
if(stats.isFile()){
let key = path.basename(pathUrl,'.js');
temp[file] = pathUrl;
}
})
}
module.exports = {
mode:'development', // 解决警告
// 单入口文件
entry:path.join(__dirname,'src/app.js'),
// 多入口文件
// entry:{
// app:path.join(__dirname,'src/app.js'),
// app2:path.join(__dirname,'src/app2.js')
// }
output:{
path:path.join(__dirname,'dist'),
filename:'buildle.js'
},
// webpack文件解析器,用来解析各种loader
module:{
rules:[
{
test:/\.css$/,
loader:ExtractTextPlugin.extract({ // 样式的抽离
fallback:'style-loader',
use:'css-loader'
})
},{
test:/\.(jpg|png|gif)/,
loader:'url-loader'
},{
test:/\.(sass|scss)$/,
loader:[
"style-loader",
"css-loader",
"sass-loader"
]
}
]
},
resolve:{
alias:{
common:path.join(__dirname,'src/....');
}
}
devServer:{ // 起服务
host:"localhost",
port:8080,
contentBase:'.', // 基准路径 . 根目录 //本地服务器所加载的页面所在的目录
overlay:true, // 将错误显示在页面中
inline:true, // 当源文件发生改变是自动刷新页面
hot:true, // 模块的热替换
stats:'errors-only', // 只打印错误
compress:true // 当他为true时对所有的服务器资源采用gzip压缩
before(app){
app.get('/api',(req,res)=>{
res.end()
})
}
}
plugins:[
new webpack.HotModuleReplacementPlugin(), // 模块的热替换
new ExtractTextPlugin('common.css'), // common.css 目标目录
new HtmlWebpackPlugin({ // 新建html
title:"my first page",
filename:"index.html",
template:"./index.html",
inject:true // 默认false,true显示在body中
})
],
// devtool:"eval-source-map" 无map文件
devtool:"cheap-source-map" // 有map的压缩文件
}
// sass需要两个包
// node-sass sass-loader
4、引入 抛出
引入:
单:import Utils from './js/app.js'
多:import {PI,username,test} from './js';
抛出:
单:export default utils
多:export const PI = 3.14;
多:export let a = 6;
5、命令
webpack.optimize.commonsChunkPlugin // 实现多个文件中公共代码的提取
setup() // 为服务的中间件,可以对请求进行拦截
proxy() // 用来做代理的,可以将请求代理到别的服务
hot() // 模块的热加载
contentBase() // 用来定义静态文件的地址
webpack.ensure() // 实现文件的懒加载
Babel
1、Babel
- 是javascript的编译器/解码器/转码器/解析器
2、配置
- .babelrc
命令:
babel ./index.js -o ./_index.js
下包:
cnpm install --save-dev babel-cli babel-preset-env
{
"presets": [
"env"
]
}
babel-loader // es6转es5
Promise/Aysnc
1、es6定义变量
- var
- let
- import
- class
- function
- const
2、Promise
- 异步编程的一种解决方案
- 是一个对象
缺点
- 无法取消
Promise.all() 会包装多个实例成为一个新的promise实例
new Promise((resolve.reject) =>{
// do some async function
if(true){
// resolve 代表成功的回调
resolve(data);
}else{
// reject 代表失败的回调
reject(data);
}
})
3、异步加载图片
- 数据请求 ->接口(Interface)
- 创建图片
- 插入到页面当中
4、继承
obj1 extends obj2
如果继承就一定要在 contructor第一行家 super()方法
5、异步加载
- ajax
- 加载图片
- jsonp
6、语法唐
在不改变代码的情况下让代码更简洁
7、async
- 内置执行器
- 更好的语义
- 更广的适应性
- 返回Promise
Vue一些对比
1、methods和computed
- computed是计算属性,methods是方法。
- computed计算属性时基于它们的依赖进行缓存的
- computed只有在它的相关依赖发生改变时才会重新求值
- 而对于methods,只要发生重新渲染,methods调用总会执行该函数
- 总之:数据量大,需要缓存的时候使用computed;每次确实需要重新加载,不需要缓存时用methods。
2、computed和watch
- 计算属性是计算属性,侦听器watch是侦听器watch
- 侦听器watch是侦听一个特定的值,当该值变化时执行特定的函数
3、$ router和$route
- router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象
- route相当于当前正在跳转的路由对象。。可以从里面获取name,path,params,query等
- 打印this. r o u t e 和 t h i s . route和this. route和this.router,两个同时存在。
- 两者传参方式相同
Vue组件
1、组件是什么
- 是vue.js最强大的功能之一
- 可以扩展html元素,封装可重用代码
2、注册全局组件
Vue.component('组件名称',引入的.vue文件)
main.js
import heads from 'src/heads';
Vue.component('heads',heads)
// 然后在页面直接引用heads标签就可以了
3、prop
- 是父组件用来传递数据的一个自定义属性
- 父组件的数据需要通过props把数据传递给子组件,子组件需要显示用props选项声明’prop’
props:
//数组
imageList:{
type: Array,
default: ()=>[
{imageName:'p1',url: 'http://gplove.top/dog1.png'},
{imageName:'p2',url: 'http://gplove.top/dog2.png'},
{imageName:'p3',url: 'http://gplove.top/dog3.png'},
]
},
//对象
audio:{
type: Object,
default: ()=>{
return {audioName:'多余的解释.mp3',audioUrl:'http://gplove.top/audio1.mp3'}
}
}
},
4、自定义事件
- $on(event)监听事件
- $emit(event)触发事件
- 链接
5、组件通讯
1、同级目录
全局: window.Eventhub = new Vue();
发送:methods:{
send(){
EventHub.$emit('HowAre',this.val)
}
}
接收:mounted(){
EventHub.$on('HowAre',res=>{
this.val = res
})
}
2、父级向子级通讯(利用props)
父级:
data(){
return{
tit:'加油加油 !'
}
}
子级:
props:['tit'] 接收
<val1 :tit="tit"></val1>
3、子级向父级通讯(利用回调函数)
子级:
this.$emit('solgan',this.val)
父级:
<val1 @solgan='onSolgan'></val1>
methods:{
onSolgan(val){
this.solgan = val
}
}
4、组件components/component
- 局部( components)
多个
components:{
组件名称:{
name:
data(){
},
methods:{
},
beforeCreate:{
}
template = html字符串
// template有且只有一个子元素
}
}
- 全局(component)
Vue.component('组件名称',引入的.vue文件)
Vue路由
1、路由(外置的)vue-router
import VueRouter from 'vue-router';
import Index from './components/index.vue';
import List from './components/index.vue';
import Login from './components/index.vue';
Vue.use(VueRouter); // 注册
let router = new VueRouter({
routes:[{ // 定义多个路由
path:'/index',
component:Index
},{
path:'/list',
component:List
},{
path:'/login',
component:Login
},{
path:'/music',
component:Music,
children:[{ // 封装子路由
path:'/comd',
component:Comd
},{
path:'/search',
component:Search
}]
}]
})
app.vue // 入口文件
<router-view></router-view>
2、路由跳转路径
<router-link to="/music/recommd">推荐</router-link>
router-link === a
to === href
3、路由的原理
说实话,路由我一直也就光顾着用,没认真思考过这个问题,还是那次人家面试问了这个,我才反应过来是应该好好的了解一下了。
无刷新跳转页面,是单页应用的一大优势,用户体验好,加载速度快,vue 路由的跳转就是无刷新的,它有两种形式,可以在定义路由的时候通过 mode 字段去配置,如果不配置这个字段,那么默认使用的就是 hash 模式。
hash 模式,即通过在链接后添加 # + 路由名字,根据匹配这个字段的变化,触发 hashchange 事件,动态的渲染出页面。就有点类似像 a 链接用作页面上的锚点一样,不会刷新页面。
另外一种方式,是 history 模式,也就是使用的浏览器的 history API,pushState 和 replaceState。通过调用 pushState 操作浏览器的 history 对象,改变当前地址,同时结合window.onpopstate 监听浏览器的返回和前进事件,同样可以实现无刷新的跳转页面。replaceState 与 pushStete 不同的就是,前者是替换一条记录,后者是添加一条记录。
有关于 pushState 的用法,详见MDN 文档。这个 API 与 ajax 合起来构成的 pjax 技术,也是用于实现页面无刷新加载的一种方式,常用于 PC 长列表页面的翻页啥的~
history 相对于 hash 模式来说,最大的好处就是没有讨厌的 # 符号,比如同样一个 list 页面,在 hash 模式下,url 链接表现为 http://yoursite.com/#/list,看着就难受。在 history 模式下面,url 链接表现为 http://yoursite.com/list ,看着比较清爽~而且~相信做过微信公众号开发的都懂,这个该死的 # 有多烦人~在下面的应用场景里面我再讲下这个问题~
那么问题来了,既然 history 模式样子好看,功能也一样,为啥还是用 hash 模式的人比较多【此处没有真凭实据,我瞎说的】?因为 history 模式,还需要服务端进行配置,否则刷新页面就会产生 404 错误。这里也比较好理解啦,因为我们实际上是使用的 pushState 操作页面的跳转,而不是真的去服务器请求另外一个 list.html 文件,那按照 http://yoursite.com/#/list 这个路径,自然找不到啦~
如果是 nginx 的服务器,在 location / 里面加上 try_files $uri $uri/ /index.html; 即可。这行代码表示:如果匹配不到静态资源的路径,就将重定向到 index 页面,这样就不会出错啦~因为需要找后端小哥哥修改服务器配置文件,如果自己没有完全理解,两边又沟通不清楚的情况下,使用 history 模式的难度无疑就大了一些~不过也不是什么大问题~全看个人需要啦哈哈~
4、vue路由传参的三种方式
- 方法一
this.$router.push({
path:`/home/${id}`,
})
路由配置
{
path:"/home/:id",
name:"Home",
component:Home
}
在Home组件中获取参数值
this.$route.params.id
- 方法二
通过name来匹配路由,通过param来传递参数
this.$router.push({
name:'Home',
params:{
id:id
}
})
用params传递参数,不使用:/id
{
path:'/home',
name:Home,
component:Home
}
Home组件中获取参数
this.$route.params.id
- 方法三
path+query;query传递的参数会通过?id = xxx展示
this.$router.push({
path:'/home',
query:{
id:id
}
})
路由配置
{
path:'/home',
name:Home,
component:Home
}
获取参数的方法
this.$route.query.id
5、封装vue-router
下面只是个基础的vue-router,只可以页面切换。本篇只是为了熟悉源码,不为实际需要。
在src文件夹下新建一个文件夹myrouter,里面再新建一个index.js文件。
在原来的router文件夹里的index.js中把原来引入router的路径换为import VueRouter from ‘…/myrouter’
// 记录history对象
class HistoryRoute{
constructor(){
// 要监听的路径
this.current=null;
}
}
// vuerouter本身
class vueRouter{
constructor(options){
this.mode=options.mode||'hash'; //配置模式
this.routes=options.routes||[]; // routes路由表
this.routesMap=this.createMap(this.routes); // 调用 createMap,参数是路由表routes
this.history=new HistoryRoute;// 实例化history
this.init(); // 初始化
}
init(){
if(this.mode=='hash'){ // 判断是否是hash模式
location.hash?'':location.hash='/'; // 自动加#号。如果有hash返回空字符串。否则返回/
window.addEventListener('load',()=>{ // 监听页面加载完成
this.history.current=location.hash.slice(1); //拿到hash值,把#去掉。赋给实例化的history的current路径。
})
window.addEventListener('hashchange',()=>{ // 监听hash改变
this.history.current=location.hash.slice(1);
})
}
}
// 路径对应组件。新组合一个对象。如:{'/':Home},也就是映射。
createMap(routes){
return routes.reduce((memo,current)=>{ // current 就是路由表routes
memo[current.path]=current.component;
return memo
},{})
}
}
vueRouter.install=function(Vue){
// 写插件要注意判断插件是否注册
if(vueRouter.install.installed)return
vueRouter.install.installed=true;
// 向vue里面混入操作
Vue.mixin({
beforeCreate(){
if(this.$options&&this.$options.router){ // 在App.vue文件里如果有router选项的话
this._root=this; // 这里的this指向当前Vue实例,缓存下自身。
this._router=this.$options.router; // 挂载下选项里传进来的router.
Vue.util.defineReactive(this,'current',this._router.history); //监听this.current,并且传入第三个参数。相当于children。
}else{
this._root=this.$parent._root; //如果没有就向上查找一级,直到查到App.vue里new Vue({router})为止。
}
// 这个方法只是说明this.$router只读,私有变量思想
Object.defineProperty(this,"$router",{ //this指当前组件实例
get(){
return this._root._router; // 返回挂载后的router
}
})
}
})
// 定义组件
Vue.component('router-view',{
render(h){
let current=this._self._root._router.history.current;// 拿到当前存进去的router实例里的current
let routerMap=this._self._root._router.routesMap;//拿到当前存进去的router实例里的routesMap
return h(routerMap[current]); // 拿到routerMap,调用h方法。渲染routerMap对应关系。放到router-view组件里面。
}
})
}
// 暴露vuerouter
export default vueRouter;
6、Hash与history的使用
hash:
- 号后的就是hash的内容
- 可以通过location.hash拿到
- 可以通过onhashchange监听hash的改变
- 可以在#号后面加路径不会向服务器请求
history
- history即正常的路径
- location.pathname
- 可以用onpopstate监听history变化
Vue动画
1、transition
- name=’ ’ ->手写
- animate.css
- velocity
2、进入动画从0-1
v-enter // 进入前
v-enter-active // 定义进入过渡生效时的状态
v-enter-to // 定义进入过渡结束时的状态
3、离开动画 从1-0
v-leave // 离开前
v-leave-active // 离开中
v-leave-to // 离开后
4、过度时间
:duration='1000'
:duration='{enter:'1000',leave:'1000'}'
5、JavaScipt钩子
v-on:before-enter
v-on:enter
v-on:after-enter
v-on:enter-cancelled // 取消动画(删除)
Vue钩子
1、钩子函数
指令定义函数提供了几个钩子函数(可选) :
- bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
- inserted:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于document)。
- updata:被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后值绑定,可以忽略不必要的模板更新。
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
创建指令对象,分析放在代码中
<template>
<div>
<div class="show" v-show="show" v-clickoutside="handleClose">
显示
</div>
</div>
</template>
<script>
const clickoutside = {
// 初始化指令
bind(el, binding, vnode) {
function documentHandler(e) {
// 这里判断点击的元素是否是本身,是本身,则返回
if (el.contains(e.target)) {
return false;
}
// 判断指令中是否绑定了函数
if (binding.expression) {
// 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
binding.value(e);
}
}
// 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
el.__vueClickOutside__ = documentHandler;
document.addEventListener('click', documentHandler);
},
update() {},
unbind(el, binding) {
// 解除事件监听
document.removeEventListener('click', el.__vueClickOutside__);
delete el.__vueClickOutside__;
},
};
export default {
name: 'HelloWorld',
data() {
return {
show: true,
};
},
directives: {clickoutside},
methods: {
handleClose(e) {
this.show = false;
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.show {
width: 100px;
height: 100px;
background-color: red;
}
</style>
2、钩子函数参数
钩子函数的参数有:
- el: 指令所绑定的元素,可以用来直接操作 DOM 。
- binding:一个对象,包含以下属性:
name: 指令名,不包括 v- 前缀
value: 指令的绑定值, 例如: v-my-directive="1 + 1", value 的值是 2。
oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
expression: 绑定值的表达式或变量名。 例如 v-my-directive="1 + 1" , expression 的值是 "1 + 1"。
arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 "foo"。
modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
- vnode:Vue 编译生成虚拟节点。
- oldVnode:上一个虚拟,仅在 update 和componentUpdated钩子中可用。
Vux
1、什么是vuex?
- 每一个Vuex应用的核心就是store(仓库)。store基本上就是一个容器,它包含着你的应用中 大部分的状态(state)。
2、初始化vuex
1.下载vuex
cnpm i vuex -D
2.建立一个store文件夹(store/index.js)
// 初始化vuex
import Vue from 'vue';
import Vuex from 'vuex';
// 引入module
import app from './module/app';
Vue.use(Vuex);
// 生成一个vuex实例
export default new Vuex.Store({
modules: {
app
}
})
3.在store文件里建立一个module文件夹用来存放数据(store/ module/app.js)
// 存放数据的地方
const state = {
num: 100
}
// 派生数据(很少用)
const getters = {
doubleNum(state){
return state.num*2
}
}
// 同步改变
const mutations = {
changeNum(state, payload){
state.num = payload;
}
}
// 异步改变
const actions = {
<!--changeNumAsync(context, payload){-->
<!--}-->
changeNumAsync({commit}, payload){
commit('changeNum', payload)
}
}
export default {
// 命名空间
namespaced: true, // 配合module使用
state,
actions,
getters,
mutations
}
4.在main.js里面引入store
import Vue from 'vue'
import App from './App.vue'
import store from './store'
new Vue({
el: '#app',
store,
render: h => h(App)
})
5.在页面中使用
<template>
<div>
<button @click="changeNum('+')">+</button>
<span>{{num}}</span>
<button @click="changeNum('-')">-</button>
</div>
</template>
<script>
export default {
name: 'app',
computed: {
num() {
return this.$store.state.app.num
}
},
methods: {
changeNum(type) {
if (type == '+') {
// this.$store.commit('changeNum', this.num+1)
this.$store.dispatch('changeNumAsync', this.num+1)
} else {
this.$store.commit('changeNum', this.num-1)
}
}
},
mounted(){
console.log(this.$store)
}
}
</script>