Vue2.0学习

一 、VUE学习

简介

1.两个特性

  • 数据驱动视图

    数据的变化会导致视图的更新

  • 双向数据绑定

    数据源变化,视图也会更新

    视图中的数据变化也会同步到数据源
    Vue2使用Object.defineProperty()来监听数据的变化,实现数据驱动视图。

3.MVVM

  • 什么是mvvm

    model view viewmodel

    model数据源

    view当前页面的dom

    viewmodel表示vue的实例可以实现model和view的双向绑定

基本使用

1.基本实例化

  • 基本使用
1.绑定el和使用$mount()函数绑定作用一致
2.$mount()可以复用,而el在内部进行了绑定
<body>
    <div id="app">{{ msg }}</div>
    <!-- {{}}可以替换数据 -->
    <script>
        const vm = new Vue({
            el: "#app", //控制哪个dom,
            data: {
                // 使用哪些数据
                msg: "hellovue"
            }
        })
    </script>
</body>
  • 需要创建一个根div app熟悉这习惯

2.调试

dev tool,谷歌插件

3.指令

1.内容渲染指令

  • 指令包含

    1.v-text 替换为文本
    2.{{}} 替换为文本
    3.v-html 可以解析html标签并替换
    
  • 基本使用

<body>
    <div id="app">
    	<p v-text="msg2">嗨嗨</p>
        <p >嗨嗨{{msg}}</p>
        <p v-html="msg2">嗨嗨</p>
    </div>
    <!-- {{}}可以替换数据 -->
    <script>
        const vm = new Vue({
            el: "#app", //控制哪个dom
            data: {
                // 使用哪些数据
                msg2:"<h1>hello</h1>"
            }
        })
    </script>
</body>
  • 差异对比
1.v-text 和{{}}
将值替代为普通文本
{{}}不会覆盖原有文本
v-text会覆盖原有的文本

2.v-html会解析值的html标签信息
谨慎使用,用户可能用它来进行攻击

2.属性绑定指令

  • 指令包含
v-bind:xxx=""  简写为  :
  • 可以在插值和属性中使用

    简单的js表达式,

    调用函数的返回结果,

    进行简单的字符串拼接等等

3.事件绑定指令

  • 指令包含
v-on:xxx=""  简写为  @
  • 函数的简写

    1.可以省略function
    2.可以使用箭头函数
    methods:{
    	hello:function(){return 1;},
    	hello2(){alert(2)},
    	hello3:()=>alert(3)
     }
    
  • 方法中访问当前对象

    1.通过this访问当前对象
    2.通过vm,实例化的对象名称访问当前对象
    countadd1(){this.count+=1},
    countadd2(){vm.count+=2;}
    
  • 绑定事件的时候可以选择传递参数,函数定义的时候定义了参数,绑定的时候必须传递参数

  • 不传参的情况下默认有个参数为event e

    <button @click="countadd(9)">+9</button>
    countadd(n){this.count+=n},
    
  • 源生事件绑定

    源生的dom事件如onclick,oninput,onkeup
    将on提前,v-on:click,v-on:input
    或者@click,@input
    
  • 事件参数event

    1.如果没有传入参数,可以使用形参e接受事件目标
    <button @click="countadd1">+1</button>
    

countadd1(e){console.log(e)},
2.如果传入了参数,需要接受源生事件dom参数,需要使用$event
<button @click="countadd1($event)">+1
countadd1(e){console.log(e)},
3.使用e.target获取事件的目标


+ 事件修饰符

内外层绑定了同名函数
.prevent组织标签默认行为,可以自定义事件
.stop阻止事件冒泡传播
.capture由当前向内冒泡反冒泡
.self只在当前元素触发事件
.once只触发一次
.passive不想阻止事件的默认行为


+ 按键修饰符

1.按键码

在按键的时候判断按键是否是某个特殊的键
替代原来的按键码,按键码被摈弃了,新的浏览器不在支持按键码
字母的话有数字组成特定的按键码
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right


2.系统修饰符

在响应键盘和鼠标事件的时候必须同时按下系统按键才响应
.ctrl
.alt
.shift
.meta

Do something
```

.exact修饰符

需要精准按键,仅仅按下某系统按键的时候才触发

鼠标按键修饰符,鼠标左键,中键,右键的点击事件时候触发

.left
.right
.middle

4.双向绑定指令

  • v-model 在不操纵dom的情况下操纵表单数据

  • v-model内部会判断input的类型,或者从属于哪一种表单元素

  • input,textarea,button等使用v-model,可以操纵值和变量事件

  • value的绑定是单向绑定,数据源变化可以致使视图变化,视图变化不会导致数据变化

  • v-model

    input  radio,checked都可以
    textarea  内容
    select option
    
  • v-model的修饰符

    .number 自动转换成数字  在字符串拼接时候数字化
    .trim   自动去掉两边空白
    .lazy 在change更新非input事件更新 比如输入、删除后失去焦点的时候
    

5.条件渲染指令

  • 条件渲染指令v-if和v-show

  • v-if和v-show对比

    v-if   默认为false,则不渲染,更省资源
    v-show 频繁切换的时候,使用,避免重复渲染
    
  • v-if的相关if else

    v-if
    v-else
    
    v-if 
    v-else-if
    ……
    v-else
    

6.列表渲染指令

  • v-for的基本使用

  • 遍历数组

    1.遍历数组
    <div v-for="it in list">
    	<p>{{it.id}}-{{it.name}}</p>
    </div>
    2.额外用index获得元素的下标0开始
    <div v-for="(it,index) in list">
    	<p>{{it.id}}-{{it.name}}-{{index+1}}</p>
    </div>
    data: {
    	list:[{id:"#1",name:"张三"},
    	{id:"#2",name:"王五"},
    	{id:"#3",name:"赵四"},]
    },
    
  • 遍历对象

    可以通过v-for遍历对象
    value表示值,name表示键,index表示下标
    <div v-for="(value, name, index) in object">
      {{ index }}. {{ name }}: {{ value }}
    </div>
    
  • v-for的时候可以访问父级区域的数据,根元素的Vue对象的data数据均可访问

  • 官方推荐绑定:key

    最好是绑定id,在.vue文件中使用v-for不绑定key报错,key只能是字符串或数字

    index和key绑定没有意义,因为index和数据不强制绑定

  • 数组变更的方法,会双向绑定渲染到v-for

    push()
    pop()
    shift()
    unshift()
    splice()
    sort()
    reverse()
    
  • 可以结合一些函数,和计算属性,对数据进行筛选等操作

    filter()`、`concat()` 和 `slice()
    
  • 列表渲染的小操作

    1.循环渲染
    

4.过滤器 侦听器 计算属性

https://www.bilibili.com/video/BV1zq4y1p7ga?p=64

1.过滤器filter

  • 基本使用和定义

     1.使用 | 过滤符号 加过滤器名进行过滤
     2.在filters(和methods同级)里定义过滤器函数
     3.过滤器必须需要有返回值
     4.过滤器会默认将|前的源数据作为参数,在过滤器函数中可以接受到
     {{msg | daxie}}
     filters:{
     	daxie(val){
     		console.log("guolv"+val);
     		return val;
        }
    },
    
  • 私有过滤器和全局过滤器

    1.基本概念
    在vue实例下filters定义的是私有过滤器,不可以被其他vue实例使用
    可以使用Vue.filter(name,function)定义注册一个全局过滤器给多个vue实例调用
    2.构造
    Vue.filter(name,function(val){})接受两个参数,第一个是过滤器的名称,第二个是过滤函数
    //可以简写
    3.作用域
    全局过滤器和私有过滤器重名,根据作用域,就近原则调用私有过滤器
    
  • 过滤器使用

    1.可以使用过滤器,格式化一些内容,比如将时间格式化年元日时分秒
    2.过滤器可以调用a|b|c,将a过滤b后再传入c再过滤
    3.过滤器可以传参数,第一参数位置默认为传入数据源|前的内容
    4.Vue3中摒弃了过滤器
    

2.侦听器watch

  • 侦听器的作用

    侦听数据的变化
    
  • 基本属性和用法

    1.在watch里面定义函数
    2.函数名和数据的名称相同
    3.有两个参数,一个新值,一个旧值
     <div id="app">
     	<input type="text" v-model="msg">
     </div>
     Vue.config.devtools = true
     const vm = new Vue({
     el: "#app", //控制哪个dom
         data: {
         // 使用哪些数据
        	 msg:"hello world"
         },
         watch:{
        	 msg(newval,oldval){
         		console.log(newval+":"+oldval);
         		}
     	},
    })
    
  • 对象形式的侦听器和immediate属性

    1.如果需要创建一个刷新页面就处理的侦听器需要使用对象形式创建
    2.将immediate属性设置为true就可以刷新页面就进入侦听状态
    3.使用immediate,没更新,获得的数据为undefined
    const vm = new Vue({
        el: "#app", //控制哪个dom
        data: {
            // 使用哪些数据
            msg:"hello world"
        },
        watch:{
            msg:{
                handler(newval,oldval){
                console.log(newval+":"+oldval); 
                console.log("启动了")  
        		},
        		immediate:true
        	}
        },
        
    })
    
  • deep深度监听

    1.为了方便使用方法定义法,如果需要特殊需求,则使用对象定义法定义watch
    2.侦听对象内部的数据变化,深度监听,需要使用对象定义法进行侦听,将对象定义法中的deep属性设置为true
    watch:{
        msg:{
            handler(newval,oldval){
                console.log(newval); 
                console.log(oldval)  
            },
            immediate:true,
            deep:true
        }
    },
    

3.计算属性computed

  • 计算属性作用

    1.本质上是一个属性,通过一系列的函数计算获得
    2.可以作为vue对象的属性直接使用
    

5.axios数据请求

https://www.bilibili.com/video/BV1zq4y1p7ga?p=75

1.简介

1.用于发起网络请求的库
2.axios的返回值是一个Promise对象
3.后端接口程序返回了一个data是真实数据
4.axios除了真实数据之外套了壳,补充至config,data,headers,request,status,statusText

2.基本用法

axios({
    method:"get",
    url:"http://127.0.0.1:5000"
}).then((res)=>{console.log(res)})

3.跨域问题

1.不同源导致的跨域问题,端口,主机号不同均会导致跨域,限制数据请求的正常进行
2.可以前端vue设置代理解决
3.后端服务器(springboot注解,flask)设置代理
4.nginx反向代理解决
5.基于jsonp的内嵌script实现跨域

4.get和post请求

  • get使用params传递参数

    axios({
        method: "GET",
        url: "http://127.0.0.1:5000/getperson",
        params: { //get
            name: "张家辉",
            age:11,
            method:"GETmethod"
        },
    }).then((res) => {
        console.log(res);
        this.person=res.data
    })
    
  • post使用data传递参数

    axios({
        method: "POST",
        url: "http://127.0.0.1:5000/getpersonPost",
        data: { //get
            name: "刘嘉良",
            age:12,
            method:"POSTmethod"	
        },
    }).then((res) => {
        console.log(res);
        this.person2=res.data
    })
    

5.async/await修饰axios

  • 使用场景

    必须要使用async修饰外层函数才可以用await
    await可以使得变量接受promise的返回值,这里即axios成功时的返回值
    async f2(){
        const data=await axios({
            method: "POST",
            url: "http://127.0.0.1:5000/getpersonPost",
            data: { //get
                name: "刘嘉良",
                age:12,
                method:"POSTmethod"
            },
        })
        console.log(data)
        this.person3=data.data;
    }
    

6.axios.get, axios.post简写

  • 语法

    async f2() {
    const {data: per1 } = await axios.get("http://127.0.0.1:5000/getperson", {
        params: { //get
        name: "张三",
        age: 3,
        method: "GET"
        }
    })
    this.person = per1;
    const {data: per2 } = await axios.post("http://127.0.0.1:5000/getpersonPost", {
        name: "张三",
        age: 3,
        method: "GET"
        })
    	this.person2=per2;
    }
    

6.组件

https://www.bilibili.com/video/BV1zq4y1p7ga?p=90

1.单文件组件Vue

1.单文件组件.vue文件
2.组成部分
	template  html模板  template不会被渲染,只是个虚拟的标签;
	script  js vue实例相关操作;
	style  css样式
3.组件中的data必须是一个函数,返回一个数据对象
	data(){
        return {
          name:"hellovue",
          hello:"你好"
        }
  	}
4.组件中只有一个根元素如果没有需要写一个根元素
    <template>
      <div id="app">
        <p>{{ name }}</p>
      </div>
    </template>

    <script>
    export default {
      name: "App",
      data() {
        return {
          name: "hellovue",
        };
      },
      methods: { },
    };
    </script>

    <style lang="less"></style>

2.私有局部组件的使用步骤

1.导入需要的组件
import Left from "./components/Left.vue";
2.使用components进行组件注册
3.以标签的形式使用组件

<template>
  <div id="app">
    <p>{{ name }}</p>
    <p>{{ hello }}</p>
    <Left></Left>//3.
  </div>
</template>

<script>
import Left from "./components/Left.vue";//1.
export default {
  name: "App",
  data() {
    return {
      name: "hellovue",
    };
  },
  components:{
    Left,Right//2.
  },
};
</script>
<style lang="less">
</style>

3.全局组件的注册

1.只需要注册一次全局的vue中都可以使用这个组件
2.步骤:在main.js中导入,使用vue.component方法注册
3.直接在各个vue组件中可以使用
import Quan from './components/Quan.vue'
Vue.component('myQuan',Quan);

4.组件名称

1.分为声明名称和注册名称

声明名称为组件指定的name属性
name属性首字母要大写
注册名称为局部注册或全局注册中导入并指定的名称

2.优先显示

优先展示声明的name属性的组件名称
如果没有name,则展示注册名称

5.组件的props

  • 作用

    提高组件的复用性
    
  • 用法

    1.父传子
    <template>
      <div id="app" class="quandiv">
        <p>{{ name }}</p>
        <p>{{init}}</p>
      </div>
    </template>
    
    <script>
    export default {
      name: "App",
      data() {
        return {
          name: "this is Quan",
        };
      },
      props:['init'],
    };
    </script>
    
    <Quan init='9'  ></Quan>总结
    2.两种声明方式[]{}
    props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
    props: {
      title: String,
      likes: Number,
      isPublished: Boolean,
      commentIds: Array,
      author: Object,
      callback: Function,
      contactsPromise: Promise // or any other constructor
    }
    3.普通绑定和v-bind
    <blog-post title="My journey with Vue"></blog-post>
    <blog-post v-bind:title="post.title"></blog-post>
    4.绑定一个对象的所有属性
    <blog-post v-bind="post"></blog-post>等效于
    <blog-post
      v-bind:id="post.id"
      v-bind:title="post.title"
    ></blog-post>
    6.不直接修改props
    props: ['initialCounter'],
    data: function () {
      return {
        counter: this.initialCounter
      }
    }
    7.props{
    	init:{
    		default:0,type:number,required:true
    	}
    }
    
  • 小结

    1.在子组件中定义和使用,在父组件中赋值,父传子,子组件可以操作该数据
    2.可以使用[]和{}的方式定义,其中[]无绑定的限制,使用{}可以定义数据类型
    3.可以使用普通绑定和v-bind或:的绑定方式,其中普通方式绑定的是字符串,v-bind绑定的是js表达式
    4.可以绑定布尔,数字,字符串,数组,方法,对象等作为props的赋值
    5.将一个对象的所有属性绑定,直接v-bind="post"进行赋值
    6.props是"只读"的,不要直接修改修改props,在子组件中,赋值给data,修改和使用data而不修改props
    7.用对象定义法{}定义其他属性
    	default 定义默认值
    	type 定义默认数据类型
    	required  必须传入的真假
    

6.组件之间的样式冲突

1.使用scoped解决组件之间的重名样式冲突,不影响其他组件的样式
<style lang="less" scoped>
.rightdiv{
  background: green;
  height: 200px;
  width: 200px;
  display: inline-block;
}
</style>

2.在父组件中修改子组件的样式,
  修改第三方组件库中的组件样式,使用deep
  vue组件中,在style设置为scoped时,里面写的样式对子组件是不生效的,此时可以使用 /deep/ 深度选择器。	  	(不使用scoped,/deep/不生效)
<style scoped lang="less">
.devlist-content .top /deep/ .el-input__inner {
  background-color: transparent;
  color:#fff;
  border: 1px solid #404753;
}

/deep/ .el-table th {
  background-color: rgb(36, 37, 42);
  color: #fff;
}
</style>

7.vue生命周期

https://www.bilibili.com/video/BV1zq4y1p7ga?p=104

vue组件的显示过程
vue组件,依赖vue-template-compiler 模板编译器编译后显示

创建阶段:new vue=>beforeCreate=>beforeMount=>mounted=>

运行阶段:beforeUpdate=>updated=>

销毁阶段:beforeDestroy=>destroryed
new Vue:初始化事件和生命周期函数
1.create
beforeCreate:什么也做不了
(create)	:初始化props,data,methods
created		:此之后可以操作props,data,methods等数据,经常在此之后发起请求,处理数据了
判断是否有el
么有el使用$mount(el)的方式找到要操纵的元素
在内存中编译和创建html结构
2.mount
beforeMount :一般不会使用
(mount)		:内存中的虚拟html dom被渲染
mounted		:此之后操纵虚拟dom
3.update
beforeUpdate:数据发生了变化,但虚拟dom没有重新渲染
(update)	:重新渲染dom
updated		:dom被重渲染,可以操纵变化后的虚拟dom了
4.destroy
beforeDestroy	:将要销毁,并未销毁
(destroy)		:组件销毁,销毁侦听器,数据,子组件等
destroyed		:组件销毁,生命周期结束

8.组件通信

https://www.bilibili.com/video/BV1zq4y1p7ga?p=110

1.父向子传值

使用props自定义属性进行传值
<Son :msg="message"></Son>   3
data(){
	return {
		message:'hello'
	}
}
//son:
<template>
<p> {{msg}}</p>
</template>
props:['msg']    1
1.子组件定义props
2.为了props使用安全,使用data接受props
3.父组件通过在子组件中绑定信息的形式给子组件传值

2.子向父传值

使用自定义事件
//=================父组件
    <son @change="getcount"></son>
data(){
	return{
		msgfromson:''
	}
},
methods:{
    getcount(value){
    	this.msgfromson=value,
    }
}
//=================子组件
data(){
	return {
		count=1,
	}
},
methods:{
	this.$emit('change',this.count);
}
1.父亲声明事件change
2.父亲绑定change的处理函数
3.子组件通过$emit发送数据到change事件响应

3.组件之间数据共享

1.使用eventbus事件总线进行通信
//================================
1.创建一个eventbus.js
2.发送方使用bus.$emit('事件名称',数据)
3.接收方bus.$on('事件名称',处理函数),通常在在created中接受
/=================================
import Vue from 'vue'
export default new Vue()
/=================================
<script>
import bus from './eventbus.js'
export default {
  },
  mounted(){
      bus.$emit('share','嘿嘿来了啊')
  },
};
</script>
/=================================
<script>
import bus from "./eventbus.js";
export default {
  data() {
    return {
      frombro: "",
    };
  },
  created() {
    bus.$on("share", val=>{console.log(val);
    console.log('bro:'+this.frombro)
    this.frombro=val;
    });
  }
};
</script>

解决:vue中使用eventBus遇到数据不更新的问题

https://blog.csdn.net/u010007013/article/details/89515208

4.共享方案总结

1.父向子props自定义属性
2.子向父emit自定义事件
3.父子之间可以用v-model
4.兄弟eventbus
5.后代provide、inject
6.全局的数据共享vuex

9.ref操纵dom元素

https://www.bilibili.com/video/BV1zq4y1p7ga?p=118

1.ref的作用

为了简化操作dom的操作

2.ref获取当前vue中的dom

1.给组件取ref名称name
2.通过this.$refs.name获取元素
<template>
    <div class="rootdiv">
      <h1 ref="myh1">{{title}}</h1>  //================1.
    </div>
</template>
<script>
export default {
  data() {
    return {
      title:'root组件'
    };
  },
  mounted(){
    console.log(this.$refs.myh1)//================2.
  }
};
</script>

3.ref获取子组件的dom

1.父组件中给子组件ref名
2.可以操纵自组件中的数据,调用子组件中的方法
======================父组件
<count ref="refcount"></count>
=======================操纵
 this.$refs.refcount.resetcount();//调用方法
 this.$refs.refcount.count=0//获取数据

4.this.$nextTick

1.场景:数据更新,但是dom没有重新渲染,则可能无法通过ref操纵最新的dom元素
2.通过this.$nextTick(cb),等dom重新渲染之后再操作
3.不适合放在updated()中因为每次数据变化均会更新,可能数据更新,组件又更新了
this.$refs.refcount.count=0//有问题
this.$nextTick(()=>{this.$refs.refcount.count=0})//没问题

10.数组方法

1.foreach
循环,无法终止
2.some
某一个满足条件就可终止遍历,通过return true
3.every
判断数据每一个都满足某个条件

数组总结:https://www.cnblogs.com/chaoanquan/p/16253946.html

11.动态组件

https://www.bilibili.com/video/BV1zq4y1p7ga?p=146

1.动态组件简介

动态控制组件的显示和隐藏

2.基本使用

=================================
1.正常进行组件的注册,引用
2.使用component标签占位
3.指定component的is属性绑定组件
================================
<template>
  <div id="app">
    <component :is="'Right'"></component>
  </div>
</template>

<script>
import Left from "./components/Left.vue";
import Right from "./components/Right.vue";
export default {
  name: "App",
  data() {return { }; },
  components:{Left,Right },
};
</script>

3.keep-alive的使用

1.问题:component的切换过程中原组件会被销毁,替换的组件会被创建

2.解决方案:使用keep-alive标签进行包裹,内部的组件被隐藏了,不会被销毁

3.此外,keep-alive会带来另外的生命周期状态:

​ deactivated:被缓存

​ activated:被激活

<keep-alive>
	<component :is="now"></component>
</keep-alive>

4.include,exclude

1.include:指定哪些被缓存
2.exclude:指定哪些不被缓存
3.不要同时使用这两个
<keep-alive include="Left,Right">
	<component :is="now"></component>
</keep-alive>

12.插槽

https://www.bilibili.com/video/BV1zq4y1p7ga?p=151

1.插槽简介

组件中的某一块,未确定用户动态填充内容,使用slot占位,即插槽

子组件================================
<template >
  <div id="app" class="leftdiv">
    <slot></slot>
    <p>{{ name }}</p>
  </div>
</template>
父组件=================================
<Left>
	<p>这是用户区域内容</p>
</Left>

2.v-slot

1.需要给每个插槽一个名字,否则vue会默认起名为default
2.内容会默认放到default
3.使用v-slot放到具体的某个插槽中
4.v-slot只能对组件complete和templete起作用
5.v-slot的简写形式为#
6.插槽中可以有默认内容
子组件==========================
<template >
  <div id="app" class="leftdiv">
    <slot name="slot1"></slot>
    <p>{{ name }}</p>
    <slot name="slot2">这是默认内容</slot>
  </div>
</template>
父组件==========================
<Left>
	<template v-slot:slot1>
        <p>这是用户区域slot1内容</p>
      </template>
      <template #slot2>
        <p>这是用户区域slot2内容</p>
      </template>
</Left>

3.具名插槽

1.当有多个slot的时候,为了位置的准确,需要为每个slot起名
2.默认为default,如果没有指定插槽的名称,会填充到所有的名为default的插槽中

4.作用域插槽

1.在子组件中插槽中,可以定义一些自定义数据
2.#绑定具名后,可以使用一个形参对象接收所有自定义的数据
3.形参可以自定义,最好是scope,行业默认
子组件================================================
<template >
  <div id="app" class="leftdiv">
    <slot name="slot1"></slot>
    <p>{{ name }}</p>
    <slot name="slot2" msg="来自插槽2的默认信息">这是默认内容</slot> //定义msg
  </div>
</template>
父组件=================================================
<template>
  <div id="app">
    <Left>
      <template v-slot:slot1>
        <p>这是用户区域slot1内容</p>
      </template>
      <template #slot2="scope">        //作用域插槽
        <p>这是用户区域slot2内容</p>
        <p>{{scope.msg}}</p>			//使用信息msg
      </template>
    </Left>
  </div>
</template>
4.可以动态绑定数据作用域插槽,也可以解构数据
子组件===============================
<template >
  <div id="app" class="leftdiv">
    <p>{{ name }}</p>
    <slot name="slot2" msg="来自插槽2的msg" :user="userinfo">这是默认内容</slot>
  </div>
</template>
  data() {
    return {
      userinfo:{
        name:'张三',
        age:18
      }
    };
  },
父组件=============================
<Left>
    <template #slot2="{msg,user}">
        <p>这是用户区域slot2内容</p>
        <p>{{msg}}</p>
        <p>{{user.name}}</p>
    </template>
</Left>

13.自定义指令

https://www.bilibili.com/video/BV1zq4y1p7ga?p=160

1.简介

1.v-on,v-if,v-show等,类似的,可以自定义指令

2.有全局自定义指令,全局可用

​ 私有自定义指令,当前组件可用

2.私有和全局自定义指令

1.私有

1.在每个组件的directives节点下可以定义自定义指令,进行一些功能
2.有bind组件绑定的时候触发,和update组件dom更新的时候触发
3.bind,update可以简写为对象的形式
<template>
  <div id="app">
    <p>name:{{ name }}</p>
    <input type="button" value="切换" @click="change" /><br />
    <Left>
      <template #slot2="{msg,user}">
        <p>这是用户区域slot2内容</p>
        <p>{{msg}}</p>
        <p>{{user.name}}</p>
        <p v-name="color">空的</p>
      </template>
    </Left>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      name: "AppVue",
      color:'blue'
    };
  },
  directives:{
      name:{
        bind(el,binding){
          el.style.background=binding.value;
          console.log(binding.value)
        },
        update(){
          el.style.background=binding.value;
          console.log(binding.value)
        }
      }
      //=============================简写
  	name(el,binding){
    	el.style.background=binding.value;
        console.log(binding.value)
    },
  }
};
</script>

2.全局

1.使用main.js中使用Vue.directive定义指令
不简写========================
Vue.directive('color', {
    bind(el, binding) {
      el.style.color = binding.value;
    },
    update(el, binding) {
      el.style.color = binding.value;
    }
  }
)
简写===============================
Vue.directive('color',
  function (el, binding) {
    el.style.color = binding.value;
  },
)

X.VUE案例

案例1 列表渲染

  • 循环渲染中的问题

    1.input checkbox等表单元素使用v-model进行双向绑定
    2.使用v-if v-else选择渲染动态切换的已启用已禁用的状态,考虑性能选择是否用v-show
    3.在插值里写简单的js表达式,不可以写复杂语句,最终是一个值,不要有多条语句
    
  • 动态生成checked

    1.使用label 和 label中的for属性绑定input的id,可以扩大复选框的操作区域
    2.使用v-for动态生成的时候会出现for绑定重名的情况,需要借用id动态生成for的绑定
      label :for="'cb'+item.id"
    
  • 删除操作

    1.除了后台,可以使用list+数组filter的方法,传入id并进行判断,重新绑定,进行重渲染,实现删除的效果
    
  • 添加操作

    1.可以使用.prevent组织默认行为并写自己定义的行为
    2.可以使用return ,终止函数的行为
    3.表单的默认提交行为会刷新页面
    

二、 Vue-router

https://www.bilibili.com/video/BV1zq4y1p7ga?p=174

1.前端路由简介

1.什么是路由
Hash地址和组件的对应关系
2.什么是hash地址
url#符号及往后的东西叫hash地址会变化(锚链接会切换hash地址)
3.前端路由工作
用户进行相关操作,会监听到hash地址的变化,并把相关的组件渲染到页面中去
  • 简易的前端路由的启发

https://www.bilibili.com/video/BV1zq4y1p7ga?p=177

前端路由模拟所需:
1.使用动态组件标签,动态切换组件实现页面切换
2.使用window.onhashchange监听hash地址的变化
3.使用local.hash读取hash值

2.Vue Router安装和导入

Vue提供的路由组件,安装步骤如下:

1.安装vue router包
2.创建路由模块
3.导入并挂载路由模块
4.声明路由链接和占位符
1.=================================
npm install vue-router@3.5.2 -s
2.=================================
	1.创建src/router/index.js文件,这就是路由节点
	2.在index.js文件中初始化:
	在vue cli会自动生成/src/router/index.js
	===============================
	//1.导入包
	import Vue from 'vue';
	import VueRouter from 'vue-router'
	//2.把vue router安装为插件
	Vue.use(VueRouter)
	//3.创建实例对象
	const router=new VueRouter()
	export default router
	===================================
3.=====================================
    //在main.js文件下挂载router节点
    import router from './router/index.js'
    Vue.config.productionTip = false
    new Vue({
      render: h => h(App),
      router
    }).$mount('#app')
4.================================
	1.在需要展示的页面中对应位置写上占位符router-view,组件会渲染到该位置
	=========================================
	<template>
      <div id="app">
        <p>{{ name }}</p>
        <p>{{ hello }}</p>
        <a href="#/Left">Left </a> &nbsp;
        <a href="#/Right">Right </a>
        <router-view></router-view>
      </div>
    </template> 
	========================================
	2.在router/index.js文件中声明路由关系,添加routes节点
	=========================================
	const router=new VueRouter({
        routes:[
            {path:'/left',component:Left},
            {path:'/right',component:Right}, 
        ]
	})
	==========================================

Tips

1.可以使用router-view占位
2.可以使用router-link代替a链接
	差异==================
	1.使用to代替href
	2.不用写#
	使用==================
	<a href="#/left">Left </a>
    <router-link to="/left">这是router link left</router-link>
3.使用redirect重定向,可写一个默认路由,或者重定向一个路由
    const router=new VueRouter({
        routes:[
            {path:'/',redirect:'/left'},
            {path:'/left',component:Left},
            {path:'/right',component:Right}, 
        ]
    })

3.Vue Router的简单使用

https://www.bilibili.com/video/BV1zq4y1p7ga?p=180

4.嵌套路由

https://www.bilibili.com/video/BV1zq4y1p7ga?p=183

1.简介

通过路由实现组件的嵌套展示,组件的嵌套展示

2.实现

1.子组件中的节点声明
2.子组件的组件导入
3.嵌套路由的抒写
4.嵌套路由的默认路由,重定向
//===================================================
<template>
  <div id="app" class="rightdiv">
    <p>{{ name }}</p>
    <router-link to="tap1">二级组件1</router-link>&nbsp; //1
    <router-link to="tap2">二级组件2</router-link>    
    <router-view></router-view>               //1
  </div>
</template>

<script>
import Tap1 from './Tap1.vue'       //2
import Tap2 from './Tap2.vue'       //2
export default {
  name: "Right",
  data() {
    return {
      name: "this is right",
    };
  },
  components:{Tap1,Tap2 }         //2
};
</script>
//=======================================
//1.导入包
import Vue from 'vue';
import VueRouter from 'vue-router'

import Left from '@/components/Left.vue'
import Right from '@/components/Right.vue'
import Tap1 from '@/components/Tap1.vue'
import Tap2 from '@/components/Tap2.vue'
//2.把vue router安装为插件
Vue.use(VueRouter)
//3.创建实例对象
const router=new VueRouter({
    routes:[
        {path:'/',redirect:'/left'},
        {path:'/left',component:Left},
        //3==========================================
        {	path:'/right',
        	component:Right,redirect:'/right/tap1',//4=======
        	children:[
            {path:'tap1',component:Tap1},
            {path:'tap2',component:Tap2}
        ]}, 
    ]
})
export default router

5.动态路由

https://www.bilibili.com/video/BV1zq4y1p7ga?p=186

1.简介

概念引入:

​ 路径参数:hash路径中的参数,#后的叫路径参数,用this.$route.params

​ 查询参数:?后的参数叫查询参数,用this.$route.query获取查询参数

2.基础使用

1.正常导入组件,和普通路由一样
2.父组件中路由自己写参数
3.路由中使用冒号定义动态参数项
4.获取参数项的值,有以下的方式:
	1.通过子组件中this.$route.params.参数名 获取参数
	2.路由中开启props设置为true,开启路由传参
//==============================2
<template>
  <div id="app">
    <p>{{ name }}</p>
    <p>{{ hello }}</p>
    <a href="#/left">Left </a> &nbsp;
    <a href="#/right">Right </a>&nbsp;
    <!-- ======================================动态路由2 -->
    <router-link to="/space/1">洛基</router-link>&nbsp;
    <router-link to="/space/2">雷神</router-link>&nbsp;
    <router-link to="/space/3">海拉</router-link>&nbsp;
    <router-view></router-view>
  </div>
</template> 
//==============================3
routes:[
        {path:'/space/:id',component:Space},//3============
        {path:'/',redirect:'/left'},
        {path:'/left',component:Left},
        {path:'/right',component:Right,redirect:'/right/tap1',children:[
            {path:'tap1',component:Tap1},
            {path:'tap2',component:Tap2}
        ]}, 
    ]
//=================================4.1
<template>
  <div id="app" class="spacediv">
    <p>{{ name }}</p>
    <p>spaceid:{{this.$route.params.id}}</p>
    <router-view></router-view>
  </div>
</template>
//===========================4.2
	//4.2.1子组件中开启props,并使用
    <template>
      <div id="app" class="spacediv">
        <p>{{ name }}</p>
        <p>spaceid:{{this.$route.params.id}}</p>
        <p>props spaceid:{{id}}</p>     //4.2.1===========
        <router-view></router-view>
      </div>
    </template>

    <script>
    export default {
      name: "Space",
      props:['id'],  //4.2.1==============
      data() {
        return {
          name: "this is space",
        };
      },
    };
    </script>
	//=====================4.2.2 路由中开启props
 	{path:'/space/:id',component:Space,props:true},

3.tips

this.$route.path是不完整的路径 ,不包含查询参数

this.$route.fullPath包含查询参数

6.导航

1.编程式导航

  • 概念

    和普通的点击链接进行导航,这种叫声明式导航相区别,可以使用编程式导航

    vue提供了this.$route系列的api叫编程式导航

  • 常用api

    1.$this.route.push('hash地址') 会增加一条历史记录
    2.$this.route.replace('hash地址') 会替换当前的历史记录
    3.$this.route.go(数值n) 前进n层,负数则后退
    4.可以在行内html标签内使用编程式跳转,这时候this要省略,直接用$router
    //1=============================
    <input type="button" value="跳转到海姆达尔" @click="hai"/>
    hai(){this.$router.push('/space/4');}
    //2=============================
    <input type="button" value="跳转到海姆达尔" @click="hai"/>
    hai(){this.$router.replace('/space/4');}
    //3=================================
    this.$router.forward()
    this.$router.back()
    this.$router.go(n)
     n>0 前进n
     n=0 刷新
     n<0 后退
    

2.导航守卫

https://www.bilibili.com/video/BV1zq4y1p7ga?p=190

简介

可以控制访问权限,进行一定的拦截

1.全局守卫

1.在router中的index.js中使用router.beforeEach进行全局守卫
2.to即将访问的路由信息
  from即将离开的路由信息
  next使用next()放行否则不可跳转
router.beforeEach((to,from,next)=>{
    console.log(to);
    console.log(from);
    next();
})

2.next的放行方式

1.next()            //放行
2.next('hash地址')  //跳转到某一页面
3.next(false)  //当前页面

4.登录验证案例

1.

三、Vuex

https://www.bilibili.com/video/BV1ea411A7GF/?spm_id_from=333.788.recommend_more_video.4

1.简介

为了方便大型项目的数据共享,减少数据父子关系对数据共享的限制

将store作为中间站,不再进行复杂的数据传递

vuex中的数据是响应式的,可以实现数据和视图的响应

2.安装

注意vue和vuex的版本是相互对应的!

1.npm install vuex -s安装
2.src/store/store.js创建文件
3.初始化2.中的文件
	import Vue from 'vue'
    import Vuex from 'vuex'
    Vue.use(Vuex)
    export default new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        increment (state) {
          state.count++
        }
      }
    })
4.挂载到main.js中
	import store from './store/store.js'
    Vue.config.productionTip = false
    new Vue({
      store,
      render: h => h(App),
    }).$mount('#app')

3.核心概念

1.State

https://www.bilibili.com/video/BV1ea411A7GF?p=5

state vuex的基础数据

1.在store.js中进行数据定义
2.通过两种方式使用使用mapState展开到computed中
1.数据定义=============================
    export default new Vuex.Store({
      state: {
        count: 0
      },
    })
2.数据使用============================
	2.1this.$store.state.count=====================
	console.log(this.$store.state.count);
	2.2 mapState 结合计算属性
	import { mapState } from 'vuex';//js中导入
	computed:{
    	...mapState(['count'])//计算属性中展开,这样就可以直接使用count
  	},

2.Mutation

https://www.bilibili.com/video/BV1ea411A7GF?p=7

不要直接修改state中的数据,不利于数据维护

不要在mutation中执行异步任务

vuex中使用mutation来修改state中的数据

1.有参数的mutation
2.无参数的mutation
3.使用mapmutations的方式使用mutation,在methods中展开
1.无参数的mutation========================
//store.js定义
mutations: {
    add (state) {
    	state.count++
    },
}
//组件中使用
handleadd(){
      this.$store.commit('add');
}
2.有参数的mutation=======================
//store.js定义
mutations: {
    minus(state,name){
    	state.count-=name;
    }
}
//组件中使用
handleminus(){
	this.$store.commit('minus',2)
}
3.mapmutations==================
组件中的methods中展开
methods: {
    ...mapMutations(['minus']),
    handleminus(){
        this.minus(2);
    }
},

3.Action

https://www.bilibili.com/video/BV1ea411A7GF?p=10

mutation只能执行同步任务,需要在action中进行异步任务

action中是间接执行mutation中的函数

1.定义mutation(第一个参数必要,第二个可以自定义参数)
2.使用this.$store.disparch触发mutation(可以自定义参数,类比mutation)
3.触发的另外方式mapActions,在methods中展开
1.=================mutation定义
mutations: {
    add (state) {
      state.count++
    },
  },
actions:{
  	addasync(context,name){
     	setTimeout(() => {
        context.commit('add',name);
      }, 1000);
    }
  }
2.触发mutation=============================
this.$store.dispatch('addasync',3);
3.mapActions==================
import { mapState,mapActions } from 'vuex';
methods: {
    ...mapActions(['addasync']),
    handleadd(){
      // this.$store.commit('add');
      // this.$store.dispatch('addasync',3);
      this.addasync(4);
    }
  },

4.Getter

https://www.bilibili.com/video/BV1ea411A7GF?p=13

类似于state的计算属性

1.getter的定义和使用
2.使用mapGetters展开到计算属性,然后当做计算属性一样用
1.getter的定义和使用==================
state: {
    count: 0
  },
getters:{
  	getcount:(state)=>state.count,
},
//使用:
this.$store.getters.getcount
2.mapGetters======================
computed:{
    ...mapState(['count']),
  },
<p>countget:{{getcount}}</p>

5.Module

可以将store中分块

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

4.WebStorage穿插

1.各种存储的区别

cookie session 参与网络通信,存储于本地 H4的策略

sessionStorage cookieStorage 都是web本地存储,不参与网络通信 H5的策略

cookie 存储在客户端 webstorage用以替代cookie,只能存键值对

session 存储在服务器端,用户和服务器长时间没有会话就失效,可以存对象

cookie有一些限制,所以H5改成webstorage:

​ 1.存储大小 只能20个

​ 2.需要在客户端服务器中传输,消耗资源

​ 3.安全性问题

localstorage 存储在本地,永久有效

**sessionstorage **存储在本地,关闭页面就失效

2.使用方式

2.1 cookie session

2.2 localstorage sessionstorage

只能存储字符串,如果要存对象需要使用JSON.stringify();JSON.parse();进行转换

key(n) 该方法用于返回存储对象中第n个key的名称
setItem(key, value) 该方法接收一个键名和值作为参数,将会把键值对添加到存储中,如果键名存在,则更新其对应的值
getItem(key) 该方法接收一个键名作为参数,返回键名对应的值
removeItem(key) 该方法删除键名为key的存储内容
clear() 该方法清空所有存储内容
length 该属性返回Storage存储对象中包含的item的数量

四、Vue-cli

1.创建、配置、启动

1.创建过程

1.使用vue create xxx创建项目尽量不要中文
2.选项:最后一个手动
	yushe ([Vue 2] babel, eslint)
  	Default ([Vue 2] babel, eslint)
 	Default (Vue 3 Preview) ([Vue 3] babel, eslint)
  	Manually select features
3.手动选择
? Please pick a preset: Manually select features
? Check the features needed for your project:
 (*) Choose Vue version
 (*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
 ( ) Vuex
 (*) CSS Pre-processors
 ( ) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing
4.配置信息放在哪儿,选独立的配置值
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
  In package.json
5.? Save this as a preset for future projects? (y/N)选择预设

2.项目启动

$ cd 目录
$ npm run serve开发
$ npm run build上线
ctrl+c停止

2.目录文件介绍

1.public中:
	默认一个图标
	index.html启动页面,vue组件会被注入到这之中形成页面
2.src:
	源代码目录
	assets  静态资源,如图片等
	components   封装的组件
	main.js    项目的入口文件
	app.vue   根组件,如果需要修改

项目的运行过程

1.同过main.js将app.vue渲染到html
2.app.vue中内嵌了其他封装好的组件
3.main.js行为:将app.vue替换index中的app div
new Vue({
  render: h => h(App),
}).$mount('#app')
$mount的作用,指定操纵的元素效果相当于指定vue对象的el

Webpack

1.基础学习

1.基本使用

创建一个隔行变色的效果

1.新建目录,在目录下按cmd进入命令行,npm init -y命令,初始化配置文件package.json,
2.目录中新建src文件夹,新建一个index.html,index.js
3.初始化页面结构,创建无序列表
4.安装jquery,使用npm install jQuery -S,会安装到dependencies中
5.使用ES6导入jquery

2.安装webpack

  • 后缀介绍

    -S --save开发阶段和上线都要用

    -D --save-dev开发阶段使用仅仅

    npmjs.com中查询使用哪个后缀
    
  • 安装命令

    使用
    npm install webpack@5.42.1 webpack-cli@4.7.2 -D
    
  • 在项目中配置webpack

    1.项目根目录中创建webpack.config.js,初始化

    module.exports={
    //有development和production
        mode:'development'
    }
    

    2.package.json scripts节点下新建dev可以使用npm run dev

     "scripts": {
        "dev":"webpack"
      },
    
  • 导出后装包

    1.除了模块其他可以复制
    2.复制完了后使用npm i装包
    

Now

https://www.bilibili.com/video/BV1zq4y1p7ga?p=177

Tips

1.模块化导入的时候,当不指定文档名会默认导入文件夹中的index.js文件

posted @ 2022-03-30 10:21  超安全  阅读(215)  评论(0编辑  收藏  举报