Vue知识点

这里写目录标题

VUE

1.Vue是什么?

  • Vue是一个渐进式的javaScript开发框架,通过组建的开发,最后合并组件形成页面。
  • 构造器(构造函数)
  • 自动化构建工具
优点
  1. 组建化开发
  2. 单页面路由
  3. 丰富的Api方法
  4. 双向的数据绑定
  5. 单向数据流
  6. 易于结合其他第三方库
缺点
  1. 生态系统不够完善
  2. 可扩展性稍差

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、结构赋值

  • 三种状态
    1. 模式不匹配
    2. 结构不成功:声明了变量,没有复制( undefined )
    3. 不完全结构
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 typePromise.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定义变量

  1. var
  2. let
  3. import
  4. class
  5. function
  6. const

2、Promise

  • 异步编程的一种解决方案
  • 是一个对象

缺点

  1. 无法取消
Promise.all()  会包装多个实例成为一个新的promise实例

new Promise((resolve.reject) =>{
    // do some async function
    if(true){
        // resolve 代表成功的回调
        resolve(data);
    }else{
        // reject 代表失败的回调
        reject(data);
    }
})

3、异步加载图片

  1. 数据请求 ->接口(Interface)
  2. 创建图片
  3. 插入到页面当中

4、继承

obj1 extends obj2
如果继承就一定要在 contructor第一行家 super()方法

5、异步加载

  1. ajax
  2. 加载图片
  3. jsonp

6、语法唐

在不改变代码的情况下让代码更简洁

7、async

  1. 内置执行器
  2. 更好的语义
  3. 更广的适应性
  4. 返回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. routethis.router,两个同时存在
  • 两者传参方式相同

Vue组件

1、组件是什么

  1. 是vue.js最强大的功能之一
  2. 可以扩展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

  1. 局部( components)
多个
components:{
    组件名称:{
        name:
        data(){
            
        },
        methods:{
            
        },
        beforeCreate:{
            
        }
        template = html字符串
        // template有且只有一个子元素
        
        
    }
}
  1. 全局(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

  1. name=’ ’ ->手写
  2. animate.css
  3. 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、钩子函数参数

钩子函数的参数有:

  1. el: 指令所绑定的元素,可以用来直接操作 DOM 。
  2. 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 }
  1. vnode:Vue 编译生成虚拟节点。
  2. 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>

链接一
链接二

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值