Vuejs基础教程
一、Vue概述
- 前端三大框架
- 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"
}
})
}
- 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>
- 图片显示:引入图片
<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>
- 事件绑定
- 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>
- 事件修饰符详解
- .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>
- 课后练习
- 制作一个计数器,点击+,计数器数值增加,点击-,计数器数值减小,且不能小于零。
<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. 项目文件夹的组成
- node_modules:存放项目功能模块
- public:存放的是项目所需的静态文件
- src(*):后续的开发工作都会在此文件夹下进行
- assets:存放的是功能性的静态文件
- components:Vue组件存放的文件夹
- App.vue:单页面组件的根组件
- main.js:项目的入口文件
- .gitignore:git上传到代码托管平台(github,coding,gitee) 的时候,忽略文件推送的执行文件
- babel.config.js:编译工程的配置文件
- babel:工具链,将ES6的语法转换成可兼容的JS语法
- package-lock.json/package.json:通过这个文件可以快速的创建环境依赖
npm install
- README.md:项目文件说明档
概述
- 基于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:项目的入口文件
- @vue/cli的包来创建我们的vue项目,安装代码如下所示:
npm install -g @vue/cli
- 让命令行工具进入到hello目录中,然后执行下面的命令启动项目:
npm run serve
- 项目创建目录 (1) node_modules文件夹:存放项目依赖功能包 (2) public文件夹:存放静态文件,如图片 (3) src文件夹:存放项目源文件,用于后续开发 (4) assets:存放会被修改的文件,如css和js文件 (5) components:存放局部功能组件 (6) main.js:项目入口文件 (7) App.vue:根组件
- localhost = 127.0.0.1
- 扩展名为.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>
组件化开发概述
- 以vue为后缀的文件是vue的单文件组件
- 大家可以把组件理解成一个,可以自定义的,有更大功能的标签
- 链接: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操作、过滤器
-
插槽:Vue为了实现内容的分发
-
匿名插槽/默认插槽:直接通过
<slot></slot>标签定义的插槽
<slot></slot>
- 具名插槽:为slot标签添加name属性来区分不同的插槽
<slot name="header"></slot>
<template v-slot:header></template>
- 作用域插槽:作用域插槽其实就是带数据的插槽,即带参数的插槽
<slot name="slotThree" :fruits="arr"></slot>
<template v-slot:slotThree></template>
- 通过插槽获取元素的索引值
<template v-slot:default="scope">
<button @click="del(scope.$index)"></button>
</template>
- 获取真实DOM:通过ref属性为元素添加信息,然后通过$refs来获取这个元素
<template>
<div ref="box"></div>
</template>
<script>
export default {
//window.getComputedStyle方法可以获取元素的样式。
mounted(){
console.log(this.$refs.box);
}
}
</script>
- 过滤器:用于一些常见的文本格式化
<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.插槽
插槽在项目中的应用
-
创建更加灵活、易扩展组件:自定义button,自定义tabledeng。
-
开发或使用UI库,了解组件制作原理。
-
什么是DOM
-
真实DOM:js可直接操作的获取的DOM
-
虚拟DOM:vue中的数据变化,并不是直接改变DOM,而是通过改变虚拟DOM,并计算变更差异,进而修改DOM中有的变化内容
-
vue是MVVM的架构模式
-
获取元素的引用信息的方法:vm.$refs
-
获取元素的引用信息的方法:
-
window.getComputedStyle(element).color
-
过滤器(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>
九、数据交互
- axios:是vue框架中提供的Ajax库
- 安装axios
npm install axios --save
- 引入axios
import axios from 'axios'
- 如果希望页面加载时便显示数据,可以直接将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文件是用来配置路由的,包括配置导航守卫的逻辑
- Vue create router(文件名)
- ↓ Manmally....
- ↓ > Router > <点击空格按键>
-
(*) Router > 回车
- 一直回车 > 完成
- package.json查看有没有router
概念:
- 之前讲解过的内容都是在页面中完成的
- Vue是一个单页面应用,实现多页面的效果
- components这个文件夹存放的是小功能性的组件
- views这个文件夹,存放的是页面的组件模板
- 相当于一个< a>标签;to这个属性相当于href,router-link的功能类似于< a>超链接标签
- 相当于一个视窗,它会根据路由的不同类型来呈现相应的内容
- localStorage:本地存储(html5的功能)
- localStorage.setItem("username":"admin"):将一个键值对存储到本地,设置本地存储的内容为键值对形式
- localStorage.getItem("username"):获取本地存储中的键的字段为username的值
- localStorage.clear():注销
vue中的跳转功能:this.$router.push("/") 本地存储:local(本地) Storage(存储内容) setItem:设置本地存储的内容
route:名词 vbase可以把代码都调试出来
导航守卫:
- 如果点击的不是登录页,并且处于未登录的状态,那么就要跳转登录页,阻止进入其他页
- 如果点击的不是登录页,且处于登录状态,那么正常浏览当前页面
- to:路由指向的位置
- from:原路由位置
- next:回调函数,判断完成路由导向之后所执行的函数
router.beforeEach((to,from,next)=>{
})
导航守卫的简单逻辑
- 如果点击的不是登录页,且处于未登录的状态,那么跳转登录页,阻止进入其他页面
- 如果点击的是登录页,且处于未登录的状态,那么不反应
- 如果点击的不是登录页,且处于登录状态,那么正常访问
- 如果点击的是登录页,且处于登录的状态,那么跳转首页
beforeEach:在路由分配之前
十、elementUI
安装:npm i element-ui -S
- elementUI是一个基于Vue的UI库,可以用在PC端,也可以用在移动端PC端居多
- 安装element-ui
npm install element-ui --save
-
配置element-ui的相关环境,不需要背,但是不能丢
-
看文档的要领
-
看文档一定先从头看,看不懂的先跳过,先看能看懂的
-
看懂的直接复制粘贴代码,注意细节
-
文档中有些坑,一定要基础知识牢固
-
学习文档中的各种经验,以便更好的去运用
十二、插槽
- 插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重要性
- 匿名插槽:没有name属性叫做匿名插槽
- 具名插槽:插槽加了name属性就叫做具名插槽:具名插槽可以在一个组件中出现N次,出现在不同的位置
- 作用域插槽:让插槽内容能够访问子组件中才有的数据
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>