Vue笔记

99 阅读7分钟

Vuejs基础教程

一、Vue概述

  1. 前端三大框架
  • Vue.js
  • Angular
  • React

Vue.js:轻量级的前端界面框架 功能:1.数据渲染/数据同步 2.组件化/模块化 3.其他功能:路由、ajax、数据流 Vuejs中文官网-cn.vuejs.org/ mount:挂载

  • 有两种方法可以在项目中引入Vue
    • 第一种是像引入jQuery一样,引入Vue.js文件。
    • 第二种是使用Node环境,构建基于Vue的web项目。

安装vue:npm install vue

  • $mount方法,将Vue挂载到html 手动挂载。
  • el属性,作用于$mount相同 自动挂载。
  • data属性,在Vue的实例之下添加属性。
  • {{}}可以输入一个表达式,也可以直接获取Vue实例的属性。
  • #app是挂载实例
  • 手动挂载
new Vue({
  data:{
    // Vue这个实例里面存储的属性和数据
    message:"hello world"
  }
}).$mount("#app")
  • 自动挂载
  new Vue({
    el:"#app",
    data:{
      message:"hello Vue"
    }
  })
}
  1. Vue实例:引入文字
<body>
    <!-- jQuery:主要用来操作DOM -->
    <!-- vue应用的容器 -->
    <div id="app">
        <!-- {{}}双花括号可以直接显示Vue实例的属性 -->
        {{message}}
    </div>
    <script src="js/vue.js"></script>
    <script>
        // Vue构造函数可以创建Vue的实例
        const vue = new Vue({
            data:{   //vue实例添加了一个message属性
                message:"hrllo world"
            } 
        });
        // 挂载Vue应用
        vue.$mount("#app")
    </script>
</body>
  1. 图片显示:引入图片
<body>
    <!-- jQuery:主要用来操作DOM -->
    <!-- vue应用的容器 -->
    <div id="app">
        <!-- {{}}双花括号可以直接显示Vue实例的属性 -->
        <!-- {{message}} -->
        <!-- v-bind:简写===(:直接写冒号) -->
        <h1 v-bind:title="message">hello vue</h1>
        <img :src="imgURL" alt="">
    </div>
    <script src="js/vue.js"></script>
    <script>
        // Vue构造函数可以创建Vue的实例
        const vue = new Vue({
            data:{   //vue实例添加了一个message属性
                message:"test vue",
                imgURL:"img/1.jpg"
            }
        });
        // 挂载Vue应用
        vue.$mount("#app")
    </script>
</body>
  1. 事件绑定
  • methods属性中定义的方法内部,可以使用this获取到vue的示例,也就是说我们可以进一步通过this获取到data中的属性,而且可以通过赋值的方式改变data中的属性值。
<body>
    <div id="app">
        <h1>{{title}}</h1>
        <!-- v-on:简写 == @ -->
        <button @click="showHello">弹出框1</button>
        <button @click="sayHi">弹出框2</button>
        <button @click="changeTitle">改变title</button>
    </div>
    <script src="js/vue.js"></script>
    <script>
        new Vue({
            data:{
                title:"事件绑定"
            },
            methods:{
                showHello(){
                    alert("hello")
                },
                sayHi(){
                    alert("hi")
                },
                changeTitle(){
                    this.title = "hello world";
                }
            }
        }).$mount("#app")

        // 简写:
        // new Vue({
        //     el:"#app",
        //     methods:{
        //         showHello(){
        //             alert("hello")
        //         }
        //     }
        // })
    </script>
</body>
  1. 事件修饰符详解
  • .prevent:阻止元素的默认行为
<input type="submit" @submit.prevent="form">
  • .stop:阻止事件冒泡
  • .once:只触发一次事件,代表事件只执行一次的修饰符
<body>
        <!-- 阻止元素默认行为 -->
        <div id="app">
            vue可以通过事件修饰符来去掉默认行为(prevent)
            <form @submit.prevent="showHello">
                <input type="submit">
            </form>
        </div>
        <script src="js/vue.js"></script>
        <script>
            new Vue({
                methods:{
                    showHello(){
                        console.log("提交数据")
                    }
                }
            }).$mount("#app") 
        </script>

        <!-- 阻止事件冒泡 -->
        <!-- <div id="app">
            <button @click.once="test">test</button>
        </div>
        <script src="js/vue.js"></script>
        <script>
            const vue = new Vue({
                methods:{
                    test(){
                        console.log("提交数据");
                    }
                }
            });
            vue.$mount("#app")
        </script> -->
    </body>
  1. 课后练习
  • 制作一个计数器,点击+,计数器数值增加,点击-,计数器数值减小,且不能小于零。
<div id="app">
    <button @click="sub">-</button>
    <span>{{number}}</span>
    <button @click="add">+</button>
</div>
<script src="js/vue.js"></script>
<script>
    new Vue({
        data:{
            number:0
        },
        methods:{
            add(){
                this.number++
            },
            sub(){
                if(this.number>0){
                    this.number--
                }
            }
        }
    }).$mount("#app");
</script>
  • 制作一个图片切换的功能,电子数字列表,改变img标签显示的图片。
<body>
    <div id="app">
        <img :src="url" alt="">
        <button @click="one">1</button>
        <button @click="two">2</button>
        <button @click="three">3</button>
    </div>
    <script src="js/vue.js"></script>
    <script>
        new Vue({
            data:{
                url:"img/1.jpg"
            },
            methods:{
                one(){
                    this.url = "img/1.jpg"
                },
                two(){
                    this.url = "img/2.jpg"
                },
                three(){
                    this.url = "img/3.jpg"
                }
            }
        }).$mount("#app");
    </script>
</body>

二、创建Vue项目

1. 项目文件夹的组成

  1. node_modules:存放项目功能模块
  2. public:存放的是项目所需的静态文件
  3. src(*):后续的开发工作都会在此文件夹下进行
  4. assets:存放的是功能性的静态文件
  5. components:Vue组件存放的文件夹
  6. App.vue:单页面组件的根组件
  7. main.js:项目的入口文件
  8. .gitignore:git上传到代码托管平台(github,coding,gitee) 的时候,忽略文件推送的执行文件
  9. babel.config.js:编译工程的配置文件
    • babel:工具链,将ES6的语法转换成可兼容的JS语法
  10. package-lock.json/package.json:通过这个文件可以快速的创建环境依赖
npm install
  1. README.md:项目文件说明档

概述

  1. 基于Node环境创建vue项目(正式开发)
  • 使用vue/cli创建Vue项目

    • npm install - g @vue/cli:全局安装脚手架工具
    • vue create hello:创建一个vue项目
    • npm run serve:运行创建的项目
  • vue-cli:脚手架工具,vue的前端工作平台

  • localhost = 127.0.0.1

  • components:组件

  • 扩展名为.vue那么这个文件就是vue组件

  • App.vue:vue项目的根组件

  • main.js:项目的入口文件

  1. @vue/cli的包来创建我们的vue项目,安装代码如下所示:

npm install -g @vue/cli

  1. 让命令行工具进入到hello目录中,然后执行下面的命令启动项目:

npm run serve

  1. 项目创建目录 (1) node_modules文件夹:存放项目依赖功能包 (2) public文件夹:存放静态文件,如图片 (3) src文件夹:存放项目源文件,用于后续开发 (4) assets:存放会被修改的文件,如css和js文件 (5) components:存放局部功能组件 (6) main.js:项目入口文件 (7) App.vue:根组件
  2. localhost = 127.0.0.1
  3. 扩展名为.vue那么这个文件就是vue组件

计数器代码与切换图片代码App.vue:

<!-- template:模板 -->
<!-- 组件的内容:<template>标签中只允许放置一个元素 -->
<template>
  <!-- 网页模板,编写html文件 -->
  <div id="app">
    <!-- 计数器 -->
    <!-- <button @click="sub">-</button>
    <span>{{number}}</span>
    <button @click="add">+</button> -->

    <!-- 图片切换 -->
    <img class="test" :src="temUrl">
    <button v-for=" (item , index) in arr" @click="changepic(item)" :key="index">{{index+1}}</button>
  </div>
</template>
<!-- 导入其他组件:定义该组件的数据、方法等 -->
<script>
// js代码
  var i1 = require("../img/1.jpg");
  var i2 = require("../img/2.jpg");
  var i3 = require("../img/3.jpg");
export default{
  // 计数器
  // data(){
  //   return{
  //     number:0
  //   }
  // },
  // methods:{
  //   add(){
  //     this.number++
  //   },
  //   sub(){
  //     if(this.number>0){
  //       this.number--
  //     }
  //   }
  // }

  // 图片切换

  data (){
    return{
      temUrl:i1,
      arr:[
          i1,
          i2,
          i3
      ]
    }
    
  },
  methods:{
      changepic(url){
          this.temUrl=url
      }
  }
}
</script>
<style>
/* 组件样式 */
</style>
组件化开发概述
  1. 以vue为后缀的文件是vue的单文件组件
  2. 大家可以把组件理解成一个,可以自定义的,有更大功能的标签
    • 链接:html的a标签
    • 登录:.vue组件,登录
    • 轮播图:.vue组件,轮播图
  • node_modules:存放项目依赖包
  • public:存放静态文件(例如图片等)
    • main.js为项目的入口文件
    • App.vue是单文件组

main代码解释:

// import ES2015模块语法,可以引入第三方模块。require 
// export ES2015模块语法,暴露接口,可以被其他模块调用 module。
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false   // 配置开发选项,友好的错误提示

new Vue({
  render: h => h(App),
  // render(createElement){   // createElement:可以把组件传进去
  //   return createElement(App);
  // }
}).$mount('#app')

组件化开发概述 以vue为后缀的文件是vue的单文件组件,我们在开发vue应用的过程中,主要任务就是去编写这些以vue为后缀的文件。

可以把组件理解成一个,可以自定义的,有更强大功能的标签。 而我们开发web项目,其实就是在编写和组装这些组件,例如晓舟报告的官网,可以将整个应用拆分成header,slider等等内容。

程序是如何运行的? import和export是ES2015的语法,类似于node的require和module.export

  • import:引入第三方模块,可以取代require
  • export:暴露接口,让其他模块使用当前模块

三、模块语法

1.指令

指令是带有 v- 前缀的特殊属性,在此之前我们学习过的指令如下所示:

  • v-bind:绑定事件(简写:)绑定html属性,使用【v-bind:属性名】和【:属性名】两种方式都可以绑定属性,在实际开发中,我们通常使用简写
  • v-on:绑定事件(简写@)使用【v-on:事件类型】和【@事件类型】两种方式都可以为元素绑定事件,在实际开发中,通常使用简写形式
2.条件判断

通过v-if和v-show指令可以控制元素的显示与隐藏,区别如下:

  • v-if='false':不会渲染DOM,查看元素不可见。
  • v-show='false':会渲染DOM,查看元素可见,但是样式为display:none;
  • v-for:显示列表,基于源数据多次渲染元素或模板块,使用:key来提供一个排序提示
<li v-for="(fruit,index) in fruits" :key="index">
{{index}}:{{fruits}}
</li>
3.vue中的this,代表这个vue实例
4.组件嵌套

组件命名:大写字母开头、驼峰命名 自定义组件一般在components目录中创建,命名用大驼峰的方式。

组件:组件可复用的vue实例,且带有一个数字 步骤: 创建可复用组件 需要组件的引入的文件使用:import...from.. 注册组件 在<template>标签中引入组件

App.vue代码:

<template>
  <div>
    <Header></Header>
    <Menu-List></Menu-List>
    <menu-list></menu-list>

    <!-- v-if:是不渲染dom,可以控制元素的可见性 -->
    <!-- <h1 v-if="true">hello world</h1> -->
    <!-- v-show:渲染dom,然后将元素设置为display:none -->
    <!-- <h1 v-show="false">hello world</h1> -->

    <!-- <p v-if="isLogin">欢迎:小明</p>
    <p v-if="!isLogin"><a href="">请登录</a></p> -->
    
    <!-- <ul>
      <li v-for="(fruit,index) of fruits" :key="index">
        <p>水果名称: {{fruit}}</p>
        <p>水果序号: {{index}}</p>
      </li>
    </ul> -->

    <table>
      <thead>
        <th>序号</th>
        <th>姓名</th>
        <th>年龄</th>
      </thead>
      <tbody>
        <!-- v-if="v.age==18":可以选中数组中18的人,v-if和v-for不可以在同一行代码中使用 -->
        <tr v-for="(v,i) of students" :key="i">
          <td v-if="v.age==18">{{i + 1}}</td>
          <td v-if="v.age==18">{{v.name}}</td>
          <td v-if="v.age==18">{{v.age}}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>

import Header from "./components/Header.vue";
import MenuList from "./components/MenuList";

export default{
  // 注册组件
  components:{
    Header,
    MenuList
  },
  data(){
    return {
      // isLogin:false,

      // fruits:["香蕉","草莓","鸭梨"],

      students:[
        {name:"小明",age:18},
        {name:"小红",age:19},
        {name:"小亮",age:18},
      ]
    }
  }
}
</script>

四、组件传值

1.组件之间的关系
  • 父级向子级传递数据,自定义属性
  • 子级向父级传递数据,自定义事件
  • 非父子级传递数据(同级):中间存储文件,store.js
  • props:获取当前vue实例的html属性
  • 父组件往子组件传递数据是单向传递,传递并且会报错到子组件的数据是归子组件所有,即使将传递到子组件的数据进行更改,相应的父组件的数据也不变,
  • vm.$emit(event,arg)
    • vm代表vue model,vue实例
    • $emit:创建自定义事件
    • event:事件对象,自定义事件命名
    • arg:跟随自定义事件的属性参数
  • store:仓库
  • state:状态
  • vuex:vue状态管理工具,多组件共享状态管理工具

vm.$emit(event,arg) 触发当前实例上的事件 vm指的是this

父级向子级传递数据

App代码:

<!-- 父级 -->
<template>
    <div>
	    <Child :msg="message"></Child>
    </div>
</template>

<script>
import Child from "./components/Child.vue";
export default {
	// 注册组件
	components:{Child},
	data(){
		return {
			message:"hello child"
		}
	}
}
</script>

子级代码:

<!-- 子级 -->
<template>
    <h1>{{msg}}</h1>
</template>

<script>
export default {
    props:["msg"]
}
</script>
子级向父级传递数据

购物车加数量 App.vue代码:

<template>
  <div>
    <carts></carts>
  </div>
</template>

<script>
import Carts from "./components/Carts"
export default {
  components:{Carts},
  
};
</script>

Counter.vue代码:

<template>
    <span>
        <button @click="sub">-</button>
        <span>{{qu}}</span>
        <button @click="add">+</button>
    </span>
</template>

<script>
export default {
    props:["qu","index"],
    methods:{
        sub(){
            this.$emit("sub",this.index)
        },
        add(){
            this.$emit("add",this.index)
        },
    }
}
</script>

Carts.vue代码:

<template>
    <div>
        <h1>购物车</h1>
        <ul>
            <li v-for="(v,i) of fruits" :key="i">
                {{v.name}}
                单价: {{v.price}}
                <counter
                :qu="v.qu"
                :index="i"
                @add="add"
                @sub="sub"
                ></counter>
            </li>
        </ul>
    </div>
</template>

<script>
import Counter from "./Counter"
export default {
    components:{Counter},
    data(){
        return{
            fruits:[
                {name:"苹果",price:3.14,qu:0},
                {name:"草莓",price:2.14,qu:0},
                {name:"香蕉",price:3.2,qu:0},
            ]
        }
    },
    methods:{
        add(index){
            this.fruits[index].qu++
        },
        sub(index){
            if(this.fruits[index].qu>0)
            this.fruits[index].qu--
        }
    }
}
</script>
非父子级传递数据

点击按钮改变数据 store.js代码:

export default {
    // 状态
    state:{
        message:"hello vue"
    },
    setStateMessage(str){
        this.state.message = str;
    }
}

App.vue代码:

<template>
  <div>
    <brother></brother>
    <sister></sister>
  </div>
</template>

<script>
import Brother from "./components/Brother"
import Sister from "./components/Sister"

export default {
  components:{Brother,Sister}
}
</script>

Sister.vue代码:

<template>
    <div>
        <h1>sister</h1>
        <p>{{state.message}}</p>
    </div>
</template>

<script>
import store from "../store"
export default {
    data(){
        return {
            state:store.state
        }
    }
}
</script>

Brother.vue代码:

<template>
    <div>
        <h1>brother <button @click="changeData">改变数据</button></h1>
        <p>{{state.message}}</p>
    </div>
</template>

<script>
import store from "../store"
export default {
    data(){
        return {
            state:store.state
        }
    },
    methods:{
        changeData(){
            store.setStateMessage("brother data")
        }
    }
}
</script>

五、计算属性与侦听器

1.计算属性

data属性和computed属性定义的值可以直接绑定在表达式中。如果某些值需要通过计算才能得到,那使用计算属性。

计算属性与侦听器对比 一个值的改变,会影响多个值(或处理多件事),使用侦听器。(为了观察一个值)多个值的改变,为了得到一个结果,使用计算属性。(为了得到一个值),大部分情况下都可以用computed解决。

  • computed:vue实例中的某些属性需要通过计算属性得到,需要使用到vue的计算属性
export default {
  computed:{}
}
  • watch:观察和响应Vue实例上的数据变动,叫做侦听器或侦听属性
export default {
  watch:{}
}
  • 如果关注的是一个变量的结果,使用计算属性:如果关注一个变量的改变会导致一系列行为,使用侦听属性
  • data:文本插值,存储的是vue实例中的数据和属性
  • methods:存储的是函数,vue实例的方法

App.vue代码:

<template>
  <div id="app">
    <h1>计算属性与侦听器</h1>

    <p>单价:{{price}}</p>
    <p>数量:
      <button @click="sub">-</button>
      {{quatity}}
      <button @click="add">+</button>
    </p>
    <p>折扣:{{discount}}</p>
    <p>总价:{{totalPrice}}</p>
  </div>
</template>

<script>

export default {
  data(){
    return {
      price:99,
      quatity:0,
      discount:0.5,
      totalPrice:0
    }
  },
  // 计算属性:
  // computed:{
  //   totalPrice(){
  //     return this.price * this.quatity * this.discount;
  //   }
  // },

  // 监听器:
  watch:{
    quatity(val){
      this.totalPrice = this.price * val * this.discount;
    }
  },
  methods:{
    sub(){
      this.quatity--
    },
    add(){
      this.quatity++
    }
  }
}
</script>

侦听器代码:

···
// 监听器:
watch:{
  quatity(val){
    this.totalPrice = this.price * val * this.discount;
  }
}
···

六、组件的生命周期

1.生命周期图

概念:Vue实例有一个完整的生命周期,也就是从开始创建,初始化数据,编译模板,挂载DOM,渲染==>更新==>渲染,卸载等一系列过程 我们称这是Vue的生命周期,通俗说就是Vue实例从创建到销毁的过程,就是生命周期

每个Vue实例在被创建时(new Vue)都要经过一系列的初始化过程 created()组件初始化完成 mounted()模板已创建

init:初始化 Event:事件 Lifecycle:生命周期 beforeCreate:创建之前 injections:注入 reactivity:反应 ceeated:创建 template:模板 beforeMount:挂载之前 replace:替换 created:实例创建完成后执行的函数 mounted:挂载,编译好的HTML挂载到页面完成后执行的事件钩子此钩子函数中一般会做一些ajax请求获取数据进行数据初始化 注意:mounted在整个实例中只执行一次 Update:更新 destroy:销毁、毁灭 Teardown:拆除

生命周期图: 转存失败,建议直接上传图片文件

App.vue代码:

<template>
  <div id="app">
    <h1>水果列表</h1>
    <p v-if="loading">loading...</p>
    <ul v-if="!loading">
      <li v-for="(item,index) of fruitList" :key="index">
        {{item}}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  // beforeCreate(){},
  // mounted(){
  //   console.log("这是mounted函数的内容")
  // },
  data(){
    return {
      fruitList:[],
      loading:true
    }
  },
  created(){
    this.getData();
  },
  methods:{
    // 通过计时器,模拟一个ajax获取数据的方法
    getData(){
      setTimeout(()=>{
        this.fruitList = ["香蕉","苹果","草莓"];
        this.loading = false;
      },2000)
    }
  }
}
</script>

七、插槽、DOM操作、过滤器

  1. 插槽:Vue为了实现内容的分发

  2. 匿名插槽/默认插槽:直接通过<slot></slot>标签定义的插槽

<slot></slot>
  1. 具名插槽:为slot标签添加name属性来区分不同的插槽
  <slot name="header"></slot>
  <template v-slot:header></template>
  1. 作用域插槽:作用域插槽其实就是带数据的插槽,即带参数的插槽
<slot name="slotThree" :fruits="arr"></slot>
<template v-slot:slotThree></template>
  1. 通过插槽获取元素的索引值
  <template v-slot:default="scope">
    <button @click="del(scope.$index)"></button>
  </template>
  1. 获取真实DOM:通过ref属性为元素添加信息,然后通过$refs来获取这个元素
  <template>
    <div ref="box"></div>
  </template>
  <script>
    export default {
      //window.getComputedStyle方法可以获取元素的样式。
      mounted(){
          console.log(this.$refs.box);
      }
    }
  </script>
  1. 过滤器:用于一些常见的文本格式化
  <template>
    <div>
      <h1>{{date | dateForma}}</h1>
    </div>
  </template>
  <script>
    export default {
      data(){
        return {
          date:"2020-1-1"
        }
      },
      filters:{
        dateForma(value){
            let dateTime = new Date(value);
            let year = dateTime.getFullYear();
            let month = dateTime.getMonth();
            let date = dateTime.getDate();
            return `${year}${month+1}${date}日`
        }
      }
    }
  </script>
1.插槽

插槽在项目中的应用

  1. 创建更加灵活、易扩展组件:自定义button,自定义tabledeng。

  2. 开发或使用UI库,了解组件制作原理。

  3. 什么是DOM

  4. 真实DOM:js可直接操作的获取的DOM

  5. 虚拟DOM:vue中的数据变化,并不是直接改变DOM,而是通过改变虚拟DOM,并计算变更差异,进而修改DOM中有的变化内容

  6. vue是MVVM的架构模式

  7. 获取元素的引用信息的方法:vm.$refs

  8. 获取元素的引用信息的方法:

  9. window.getComputedStyle(element).color

  10. 过滤器(filters):vue中过滤器的作用可被用于一些常见的文本格式化(也就是修饰文本,但文本内容不会改变)

App.vue代码:

<template>
    <my-button>测试文本</my-button>
</template>

MyButton代码:

<template>
    <div>
        <slot></slot>
    </div>
</template>
2.具名插槽

App.vue代码:

<template>
  <div id="app">
    <Layout>
      <template v-slot:header>
        <h1>header</h1>
      </template>
      <template v-slot:content>
        <h1>content</h1>
      </template>
      <template v-slot:footer>
        <h1>footer</h1>
      </template>
    </Layout>
  </div>
</template>

<script>
import Layout from "./components/Layout"
export default {
  components:{
    Layout
  }
};
</script>

Layout.vue代码:

<template>
    <div>
        <div class="header">
            <slot name="header"></slot>
        </div>
        <div class="content">
            <slot name="content"></slot>
        </div>
        <div class="footer">
            <slot name="footer"></slot>
        </div>
    </div>
</template>
3.获取真实DOM

App.vue代码:

<template>
    <div id="app">
        <div ref="box">hello world</div>
    </div>
</template>

<script>
export default {
  mounted(){
    let box = this.$refs.box;
    let style = window.getComputedStyle(box);
    console.log(style.height)
  }
};
</script>

<style>
div{
  width: 100px;
  height: 100px;
  background-color: red;
}
</style>
4.过滤器

通过固定算法重新组织数据。

App.vue代码:

<template>
  <div id="app">
    <h1>{{message | mySplit}}</h1>
    <h1>{{title | mySplit}}</h1>
</template>

<script>
export default {
  filters:{
    mySplit(value){
      return value.split("").join();
    }
  },
  data(){
    return {
      message : "hello",
      title:"world"
    }
  }
}
</script>
5.过滤器 日期格式化

App.vue代码:

<template>
    <div id="app">
        <h1>{{date | dateFormate}}</h1>
        <h1>{{date1 | dateFormate}}</h1>
    </div>
</template>

<script>
export default {
  filters:{
    dateFormate(value){
      let date = new Date(value);
      let year = date.getFullYear();
      let month = date.getMonth() + 1;
      let d = date.getDate();
      return `${year}${month}${d}日`
    }
  },
  data(){
    return {
      date:"2020-1-11",
      date1:"2020-11-5"
    }
  }
}
</script>

八、表单

1.双向数据绑定

v-model指令可以实现数据的双向绑定,也就是说如果input标签添加v-model指令后,在页面上修改input内的文本,会直接改变v-model绑定的变量

  • 事件名称
    • @click
    • @submit:表单的默认提交事件,@submit.prevent

App.vue代码:

<template>
  <div id="app">
    <!-- ajax实现表单的提交 -->
    <form @submit.prevent="postData">
      <div>
        <label for="">用户名</label>
        <input type="text" v-model="formData.username">
      </div>
      <div>
        <label for="">密码:</label>
        <input type="password" v-model="formData.password">
      </div>
      <div>
        <label for="">爱好:</label>
        <select v-model="formData.hobby">
          <option value="shuai">帅哥</option>
          <option value="ge">帅哥</option>
        </select>
      </div>
      <div>
        <label for="">性别:</label>
        <label for=""></label>
        <input type="radio" value="男" v-model="formData.sex">
        <label for=""></label>
        <input type="radio" value="女" v-model="formData.sex">
      </div>
      <div>
        <label for="">技能:</label>
        <label for="">坐着挣钱</label>
        <input type="checkbox" value="坐着挣钱" v-model="formData.skill">
        <label for="">富婆</label>
        <input type="checkbox" value="富婆" v-model="formData.skill">
      </div>
      <button>提交表单</button>
    </form>
  </div>
</template>

<script>

export default {
  data(){
    return {
      formData:{
        username:"",
        password:"",
        hobby:"",
        sex:"",
        skill:[]
      }
    }
  },
  methods:{
    postData(){
      console.log(this.formData);
    }
  }
}
</script>

双向数据绑定:

<template>
  <div id="app">
    <!-- 双向数据绑定 -->
    <h1>贱人名称:{{msg}}</h1>
    <input type="text" v-model="msg">
    <br>
    <br>
    <form @submit.prevent="postData">
      <span>用户名:</span>
      <input type="text" v-model="formData.name">
      <span>密码:</span>
      <input type="password" v-model="formData.password">
      <input type="submit">
    </form>
  </div>
</template>
<script>

export default {
  双向数据绑定
  data(){
    return {
      msg:"我是邵贱人",
      formData:{
        password:"",
      }
    }
  },
  methods:{
    postData(){
      console.log(this.formData.name,this.formData.password)
    }
  }
}

提交表单:

<template>
  <!-- 提交表单 -->
  <input type="text" v-model="acc">
  <input type="button" value="添加" @click="abb">
  <ul>
    <li v-for="(a,i) in acb" :key="i">{{a}}</li>
  </ul>

  </div>
</template>

<script>

export default {
  // 提交表单
  data(){
    return {
      acb:["香蕉","草莓","葡萄"],
      acc:""
    }
  },
  methods:{
    abb(){
      this.acb.push(this.acc)
    }
  }
}
</script>
<temeplate>
<div>
  <form @submit.prevent="postData">
    <label for="neme">姓名:</label>
    <input type="text" id="neme" v-model="formData.a">
    <br>
    <label for="age">年龄:</label>
    <input type="text" id="age" v-model="formData.b">
    <br>
    <label for="address">住址:</label>
    <select v-model="formData.c">
      <option value="花果山">花果山</option>
      <option value="流沙河">流沙河</option>
      <option value="高老庄">高老庄</option>
      <option value="妓院">妓院</option>
      <option value="公共厕所">公共厕所</option>
      <option value="下水道">下水道</option>
    </select>
    <br>
    <label>性别:</label>
    <label for=""></label>
    <input type="radio" value="男" v-model="formData.d">
    <label for=""></label>
    <input type="radio" value=" 女" v-model="formData.d">
    <label for=""> 未知</label>
    <input type="radio" value=" 未知" v-model="formData.d">
    <br>
    <label for="">爱好:</label>
    <label for="sport">吃粑粑</label>
    <input type="checkbox" id="tr" value="吃粑粑"v-model="formData.e">
    <label for="sport">抽风</label>
    <input type="checkbox" id="lvyou" value="抽风"v-model="formData.e">
    <label for="sport">犯贱</label>
    <input type="checkbox" id="daqiu" value="犯贱"v-model="formData.e">
    <label for="sport">发神经</label>
    <input type="checkbox" id="daqiu" value="发神经"v-model="formData.e">
    <label for="sport">给富婆搓脚</label>
    <input type="checkbox" id="daqiu" value="给富婆搓脚"v-model="formData.e">
    <br>
    <input type="button" value="提交" @click="postData">
  </form>
  <table border="1">
    <thead>
      <th v-for="(it,index) in arr" :key="index">{{it}}</th>
    </thead>
    <tbody>
      <tr v-for="(a,i) in arro" :key="i">
        <td>{{a.a}}</td>
        <td>{{a.b}}</td>
        <td>{{a.c}}</td>
        <td>{{a.d}}</td>
        <td>{{a.e.join('-')}}</td>
      </tr>
    </tbody>
  </table>
  </div>
</template>

<script>
export default {
  data(){
    return {
      arr:["姓名","年龄","住址","性别","爱好"],
      arro:[
        {a:"雪雪",b:18,c:"联合国大厦",d:"女",e:["躺着挣钱","当富婆"]},
        {a:"邵贱人",b:28,c:"搓脚店",d:"男",e:["抱富婆大腿"]},
        {a:"邵小草儿",b:44,c:"妓院",d:"非男非女",e:["吃鸡屁股","吃奥利给","吃烟头"]}
      ],
      formData:{
        username:"",
        pac:"",
        address:"",
        sex:"",
        e:[],
      }
    }
  },
  methods:{
    postData(){
      // console.log(this.formData.username)
      this.arro.push(this.formData);
      this.formData = {};
    }
  }
</div>
</temeplate>
<template>
  <div>
    <input type="text" v-model="biao">
    <input type="button" value="添加" @click="tian">
    <ul>
      <li v-for="(a,i) in arr" :key="i">{{a}}<button @click="shan">删除</button></li>
    </ul>
  </div>
</template>

<script>
export default {
  // 添加删除属性操作
  data(){
    return {
      arr:["香蕉","草莓","苹果"],
      biao:"",
    }
  },
  methods:{
    tian(){
      this.arr.push(this.biao)
    },
    shan(){
      this.arr.splice(this.arr,1)
    }
  }
}
</script>

九、数据交互

  1. axios:是vue框架中提供的Ajax库
  2. 安装axios
npm install axios --save
  1. 引入axios
import axios from 'axios'
  1. 如果希望页面加载时便显示数据,可以直接将axios方法写在created的钩子函数中
created(){
    axios.get('/data').then(function(res){
        this.goodsList = res.data;
    }).catch(function (error) {
        console.log(error);
    });
}

提交删除修改表单 App代码:

<template>
  <div>
    <form @submit.prevent="addFruit">
      <input type="text" v-model="fruit">
      <input type="submit">
    </form>
    <ul>
      <li v-for="(item,index) in fruitsArr" :key="index">
        {{item}}
        <input type="button" value="编辑"  @click="modData(index)">
        <input type="button" value="删除" @click="delFruit(index)">
      </li>
    </ul>
    <div class="box" v-show="showBox">
      <div class="motai">
        <form @submit.prevent="upDate">
          <input type="text" v-model="modFruit">
          <input type="submit" class="bt2">
          <input type="button" value="取消" class="bt2" @click="close">
        </form>
      
      </div>
    </div>
  </div>
</template>

<script>
import axios from "axios";
import "./assets/js/jquery.min.js"
export default {
  data(){
    return {
      fruitsArr:[],
      fruit:"",
      showBox:false,
      modFruit:"",
      selectedIndex:-1
    }
  },
  methods:{
    getFruits(){
      axios.get("http://127.0.0.1:3000/fruits").then(res=>{
        this.fruitsArr=res.data
      }).catch(err=>{
        console.log(err)
      })
    },
    addFruit(){
      axios.post("http://127.0.0.1:3000/fruits",{
        fruit:this.fruit
      }).then(()=>{
        this.getFruits();
      })
    },
    delFruit(i){
      axios.delete(`http://127.0.0.1:3000/fruits/${i}`).then(()=>{
        this.getFruits();
      })
    },
    modData(i){
      // this.showBox = !this.showBox;
      this.close();
      this.selectedIndex = i;
      this.modFruit=this.fruitsArr[i];
    },
    upDate(){
      axios.put(`http://127.0.0.1:3000/fruits/${this.selectedIndex}`,{
        fruit:this.modFruit
      }).then(()=>{
        this.getFruits();
        this.close();
      })
    },
    close(){
      this.showBox=!this.showBox;
    }
  },
  created(){   // 钩子函数
    this.getFruits()
  }
}
</script>
<style>
/* e*{
  margin: 0;
  padding: 0;
} */
.box{
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  background-color: rgba(184, 179, 179, 0.5);
}
.box .motai{
  width: 200px;
  height: 150px;
  background-color: rgba(75, 58, 58, 0.582);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
}
.box input:nth-child(1){
  margin: 30px 20px;
}
.box .bt2{
  margin-left: 40px;
}
</style>

javascript代码:

const Koa = require("koa");
const parser = require("koa-parser");
const router = require("koa-router")();
const cors = require("koa-cors"); // 允许跨越
const app = new Koa();

app.use(parser());
app.use(cors());

let arr = ["香蕉","草莓","苹果"];

router.get("/fruits", async ctx => {
    ctx.body = arr;
})

router.post("/fruits", async ctx => {
    let fruit = ctx.request.body.fruit;
    arr.push(fruit);
    ctx.body = true;
})

router.delete("/fruits/:index", async ctx=>{
    let ind = ctx.params.index;
    arr.splice(ind,1);
    ctx.body = true;
})

router.put("/fruits/:index",async ctx=>{
    let ind = ctx.params.index;
    let setFruit = ctx.request.body.fruit;
    arr.splice(ind,1,setFruit);
    ctx.body = true;
})

app.use(router.routes());
app.listen(3000, () => {
    console.log("running 3000");
})

十、路由

安装:

  • 通过vue-cli安装vue-router项目
  • 安装过程:
    • 1.vue create “项目名称”
    • 2.点击向下按钮选择manaolly selet features
    • 3.点击space空格选择router
    • 4.一直回车
  • views文件夹,页面的组件放到此文件夹
  • components文件夹,页面的局部功能性组件放到此文件夹
  • router文件夹中的index.js文件是路由配置文件
  • index.js文件是用来配置路由的,包括配置导航守卫的逻辑
  1. Vue create router(文件名)
  2. ↓ Manmally....
  3. ↓ > Router > <点击空格按键>
  4. (*) Router > 回车

  5. 一直回车 > 完成
  6. package.json查看有没有router

概念:

  1. 之前讲解过的内容都是在页面中完成的
  2. Vue是一个单页面应用,实现多页面的效果
  3. components这个文件夹存放的是小功能性的组件
  4. views这个文件夹,存放的是页面的组件模板
  5. 相当于一个< a>标签;to这个属性相当于href,router-link的功能类似于< a>超链接标签
  6. 相当于一个视窗,它会根据路由的不同类型来呈现相应的内容
  7. localStorage:本地存储(html5的功能)
  8. localStorage.setItem("username":"admin"):将一个键值对存储到本地,设置本地存储的内容为键值对形式
  9. localStorage.getItem("username"):获取本地存储中的键的字段为username的值
  10. localStorage.clear():注销

vue中的跳转功能:this.$router.push("/") 本地存储:local(本地) Storage(存储内容) setItem:设置本地存储的内容

router:动词router:动词 route:名词 vbase可以把代码都调试出来

导航守卫:

  1. 如果点击的不是登录页,并且处于未登录的状态,那么就要跳转登录页,阻止进入其他页
  2. 如果点击的不是登录页,且处于登录状态,那么正常浏览当前页面
  • to:路由指向的位置
  • from:原路由位置
  • next:回调函数,判断完成路由导向之后所执行的函数
router.beforeEach((to,from,next)=>{

})

导航守卫的简单逻辑

  • 如果点击的不是登录页,且处于未登录的状态,那么跳转登录页,阻止进入其他页面
  • 如果点击的是登录页,且处于未登录的状态,那么不反应
  • 如果点击的不是登录页,且处于登录状态,那么正常访问
  • 如果点击的是登录页,且处于登录的状态,那么跳转首页

beforeEach:在路由分配之前

十、elementUI

安装:npm i element-ui -S
  1. elementUI是一个基于Vue的UI库,可以用在PC端,也可以用在移动端PC端居多
  2. 安装element-ui
npm install element-ui --save
  1. 配置element-ui的相关环境,不需要背,但是不能丢

  2. 看文档的要领

  3. 看文档一定先从头看,看不懂的先跳过,先看能看懂的

  4. 看懂的直接复制粘贴代码,注意细节

  5. 文档中有些坑,一定要基础知识牢固

  6. 学习文档中的各种经验,以便更好的去运用

十二、插槽

  1. 插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重要性
  2. 匿名插槽:没有name属性叫做匿名插槽
  3. 具名插槽:插槽加了name属性就叫做具名插槽:具名插槽可以在一个组件中出现N次,出现在不同的位置
  4. 作用域插槽:让插槽内容能够访问子组件中才有的数据

App.vue代码:

<template>
  <div>
      <Mybutton>按钮</Mybutton>
      <Mybutton>重置</Mybutton>
      <Mybutton>取消</Mybutton>
      <Layout>
        <template v-slot:slotOne>
          <h1>傻逼</h1>
        </template>
        <template v-slot:slotTne>
          <h1>邵小草</h1>
        </template>
        <template v-slot:slotThree="slotData">
          <ul>
            <li v-for="(item,index) in slotData.fruits" :key="index">{{item}}</li>
          </ul>
        </template>
      </Layout>
  </div>
</template>

<script>
import Mybutton from '@/components/Mybutton';
import Layout from '@/components/Layout'
export default {
  components: { 
    Mybutton,
    Layout
  }
}
</script>

<style>

</style>

Layout.vue代码:

<template>
    <div>
        <div class="slotOne">
            <slot name="slotOne"></slot>
            <slot name="slotTne"></slot>
        </div>
        <div class="slotTwo">
            <slot name="slotTwo"></slot>
        </div>
        <div class="slotThree">
            <slot name="slotThree" :fruits="arr"></slot>
        </div>
    </div>
</template>

<script>
export default {
    data(){
        return {
            arr:["口红","眼影","睫毛膏"]
        }
    }
}
</script>

Mybutton.vue代码:

<template>
    <div>
        <button>
            <slot></slot>
        </button>
    </div>
</template>

<script>
export default {
    
}
</script>

练习1:购物车删除

App.vue代码:

<template>
  <div>
    <carts></carts>
  </div>
</template>

<script>
import Carts from "./components/Carts"
export default {
  components:{
    Carts,
  }
}
</script>

<style>

</style>

Carts.vue代码:

<template>
  <div>
    <el-form 
      ref="formData" 
      :label-position="form" label-width="70px" :model="formData">
      <el-form-item label="用户名:">
        <el-input v-model="formData.name" placeholder="请输入姓名" style="width:230px" clearable></el-input>
      </el-form-item>
      <el-form-item label="密码:">
        <el-input v-model="formData.region" placeholder="请输入密码" style="width:230px" show-password></el-input>
      </el-form-item>
      <el-form-item
          prop="email"
          label="邮箱:"
          :rules="[
            { required: true, message: '请输入邮箱地址', trigger: 'blur' },
            { type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
          ]"
        >
        <el-input v-model="formData.email" style="width:230px" placeholder="请输入邮箱地址"></el-input>
      </el-form-item>
      <el-form-item label="性别:">
        <template>
          <el-radio v-model="formData.radio" label="男"></el-radio>
          <el-radio v-model="formData.radio" label="女"></el-radio>
        </template>
      </el-form-item>
      <el-form-item label="爱好:">
        <template>
          <el-checkbox-group v-model="formData.love">
            <el-checkbox label="麻辣烫" name="love"></el-checkbox>
            <el-checkbox label="水果捞" name="love"></el-checkbox>
            <el-checkbox label="铁板鱿鱼" name="love"></el-checkbox>
            <el-checkbox label="酱肘子" name="love"></el-checkbox>
            <el-checkbox label="草莓奶昔" name="love"></el-checkbox>
          </el-checkbox-group>
        </template>
      </el-form-item>
    </el-form>
    <el-row>
      <el-button @click="postData">提交</el-button>
    </el-row>
    <br>
    <el-table
      :data="tableData"
      border
      style="width: 60%">
      <el-table-column
        label="序号"
        width="50"
        type="index">
      </el-table-column>
      <el-table-column
        prop="name"
        label="姓名"
        width="100">
      </el-table-column>
      <el-table-column
        prop="region"
        label="密码"
        width="100">
      </el-table-column>
      <el-table-column
        prop="email"
        label="邮箱地址"
        width="180">
      </el-table-column>
      <el-table-column
        prop="radio"
        label="性别"
        width="50">
      </el-table-column>
      <el-table-column
        prop="love"
        label="爱好"
        >
      </el-table-column>
      <el-table-column
        label="操作"
        width="80">
        <template slot-scope="scope">
          <el-button 
          size="mini" 
          type="danger" 
          @click="shan(scope.$index)">删除</el-button>
        </template>
      </el-table-column>
    </el-table> 
      
  </div>
</template>

<script>
export default {
  data(){
    return {
      form: 'right',
      formData: {
        name: '',
        region: '',
        email:'',
        radio:'',
        love:[]
      },
      tableData: [{
        name: '王小虎',
        region: '123456',
        email:'5294621@qq.com',
        radio:'男',
        love:'酱肘子-草莓奶昔'
      }, 
      {
        name: '王小虎',
        region: '123456',
        email:'5294621@qq.com',
        radio:'男',
        love:'酱肘子-草莓奶昔'
      }]
    }
  },
  methods:{
    shan(f){
      this.tableData.splice(f,1)
    },
    postData(){
      this.tableData.push(this.formData);
      this.formData = {
        name: '',
        region: '',
        email:'',
        radio:'',
        love:[]
      }
    }
  }
}
</script>