v-model本质上是一个语法糖
如下代码<input v-model="test">
本质上是<input :value="test" @input="test = $event.target.value">,
其中@input是对<input>输入事件的一个监听:value="test"是将监听事件中的数据放入到input,
下面代码是v-model的一个简单的例子。
在这边需要强调一点,v-model不仅可以给input赋值还可以获取input中的数据,
而且数据的获取是实时的,因为语法糖中是用@input对输入框进行监听的。
可以在如下div中加入<p>{
{
test}}</p>获取input数据,
然后去修改input中数据会发现<p></p>中数据随之改变。
v-model不仅可以给input赋值还可以获取input中的数据,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_HelloWorld</title>
<link rel="stylesheet" href="../layui/css/layui.css">
</head>
<body>
<div id="el1">
<input id="username" name="username" v-model="username">
<p>{
{
username.toUpperCase()}}</p>
<p>{
{
sex}}</p>
<p>{
{
things}}</p>
<p v-html="msg"></p><!--相当于是 innerHtml-->
<p v-text="msg"></p><!--相当于是textContent-->
<p>{
{
msg}}</p>
<!--强制数据绑定-->
<img :src="imghref"><!--src前面的: 相当于是在强制绑定-->
<!--绑定事件监听-->
<br>
<button type="button" class="layui-btn layui-btn-danger" v-on:click="test">点击一下</button>
<button type="button" class="layui-btn layui-btn-warm" @click="test1(username)">点击一下</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el:"#el1",
data:{
username:"tjk",
sex:"男",
things:"无所事事",
msg:'I will back',
imghref:"https://cdn.dragonstatic.com/parking/partner/meiguo.com/images/0.s.jpg"
},
methods:{
test(){
alert("你把爷点了");
},
test1(content){
alert(content)
}
}
})
</script>
</body>
</html>
所有vue代码中的this都指的是 vm对象本身
监视是指:所监视的属性中的值发生改变,然后进行回调函数的执行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>监视</title>
</head>
<body>
<div id="demo">
<input type="text" placeholder="First Name" v-model="firstName"><br>
<input type="text" placeholder="last Name" v-model="lastName"><br>
姓名1:(单向):<input type="text" placeholder="Full Name1" v-model="FullName1"><br>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el:"#demo",
data:{
firstName:"A",
lastName:"B"
//FullName1:"AB"
},
watch:{
firstName:function (value) {
//对firstName进行监视
alert(value); //this 就是vm实例
this.FullName1=value+""+this.lastName;
}
}
})
//第二种
vm.$watch('lastName',function (value) {
this.FullName2=this.firstName+"-"+value;
});
</script>
</body>
</html>
回调函数:1.你定义的 2.执行了 3.你没有调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>getset(双向)</title>
</head>
<body>
<div id="demo">
<input type="text" placeholder="First Name" v-model="firstName"><br>
<input type="text" placeholder="last Name" v-model="lastName"><br>
姓名1:(单向):<input type="text" placeholder="Full Name1" v-model="FullName1"><br>
姓名2:(单向):<input type="text" placeholder="Full Name2" v-model="FullName2"><br>
姓名3:(双向):<input type="text" placeholder="Full Name3" v-model="FullName3"><br>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el:"#demo",
data:{
firstName:"A",
lastName:"B"
//FullName1:"AB"
},
computed:{
//回调函数:
//1. 你定义的 2. 你没有调用 3.最终执行了
//回调函数 (当需要读取当前属性值时回调) 计算并返回当前属性的值
FullName3:{
get(){
return this.firstName+" "+this.lastName;
},
//监视特定属性的属性值,当属性值发生改变时进行回调,更新相关的属性数据
set(value){
const names=value.split(' ');
this.firstName=names[0];
this.lastName=names[1];
}
}
},
watch:{
firstName:function (value) {
//对firstName进行监视
this.FullName1=value+" "+this.lastName;
}
}
});
//监视的第二种写法
vm.$watch('lastName',function (value) {
this.FullName2=this.firstName+" "+value;
});
</script>
</body>
</html>
计算属性存在缓存,多次读取只执行一次getter计算
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>class和style的强制绑定</title>
<link rel="stylesheet" href="../layui/css/layui.css">
<style type="text/css">
.aclass{
color: red;
}
</style>
</head>
<body>
<div id="demo">
<h2>1.class绑定 :class=’xxx‘</h2>
<button type="button" :class="a">显示效果</button><br>
<hr>
<button type="button" @click="update">点击一下</button>
</div>
<h2>2. style绑定</h2>
<script src="../layui/layui.js"></script>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el:"#demo",
data:{
a:'',//相当于是声明一下
},
methods:{
//此事件是点击事件 所以点击 然后颜色会发生变化
update(){
this.a="layui-btn layui-btn-danger"
}
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-if v-else</title>
<link rel="stylesheet" href="../layui/css/layui.css">
</head>
<body>
<div id="dome">
<p v-if="xxx">床前明月光</p>
<p v-else>疑是地上霜</p> <!-- //默认是true-->
<button class="layui-btn layui-btn-danger" @click='xxx=!xxx'>点击切换</button>
<br>
<p v-show="xxx">表白呀</p>
<p v-show="!xxx">还是别了吧</p>
</div>
<script src="../layui/layui.js"></script>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el:"#dome",
data:{
xxx:true
}
})
</script>
</body>
</html>
v-if 和v-show的区别:
v-if是将整个属性进行移除 v-show是将整个控件加载完成后style设置为不显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-for</title>
</head>
<body>
<div id="dome">
<h3 >测试:v-for 遍历数组</h3>
<ul>
<li v-for="(p,index) in persons" :key="index">
--------------------------------<br>
|{
{
index}}|{
{
p.name}}|{
{
p.age}}|<button type="button" @click="deletep(index)">删除该行</button>
<button @click="updatep(index,{name:'cat' ,age:'25'})">更新该行</button>|
</li>
</ul>
<h3> 测试:v-for 遍历对象</h3>
<ul> //属性值 属性名(用处不多)
<li v-for="(value,key) in persons[1]" :key="key">
{
{
value}}:{
{
key}}
</li>
</ul>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el:"#dome",
data:{
persons:[//vue本身只监视了persos的改变,没有监视数组内部数据的改变
//vue重写了数组的一系列改变数组内部数据的方法(先调用原有的方法,然后更新界面)
{
name:"tjk",age:"13"},
{
name:"tjk1",age:"131"},
{
name:"tjk2",age:"132"},
{
name:"tjk3",age:"133"},
]
},
methods:{
deletep(index){
//删除person中指定index的p
var i=this.persons.splice(index,1);
alert(i.persons.name);
console.log(i);
//splice() 方法可删除从 index 处开始的零个或多个元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素。
},
updatep(index,newp){
//this.persons[index]=newp;//数据改变了,但是界面显示不了
this.persons.splice(index,1,newp);//可以实现增删改操作 当是增加的时候 int=0即可
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>v-for</title>
</head>
<body>
<div id="dome">
<input type="text" v-model="searchName" />
<ul>
<li v-for="(p,index) in persons" :key="index">
{
{
index}}=={
{
p.name}}=={
{
p.age}}
</li>
</ul>
=====================================================================
<ul>
<li v-for="(p,index) in filterPersons" :key="index">
{
{
index}}=={
{
p.name}}=={
{
p.age}}
</li>
</ul>
<button type="button" @click="setOrderType(1)" >按年龄升序</button>
<button type="button" @click="setOrderType(2)">按年龄降序</button>
<button type="button" @click="setOrderType(0)">原有的顺序</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el: "#dome",
data: {
dataType:0,
searchName: "",
persons: [//vue本身只监视了persos的改变,没有监视数组内部数据的改变
//vue重写了数组的一系列改变数组内部数据的方法(先调用原有的方法,然后更新界面)
{
name: "tjk", age: 13},
{
name: "tjk1", age: 131},
{
name: "tjk2", age: 132},
{
name: "tjk3", age: 133},
],
},
computed: {
filterPersons() {
//取出相关的数据
console.log(this);
const {
searchName,persons,dataType} = this;//解构赋值 相当于是 person=this.person
//最终需要希纳是的数组
let fPersons;
//对person进行过滤
//alert(persons[1].name); //将每一个数组的name中查看有无searchNmae的字符 有则赋给fPserson
fPersons= persons.filter(p=>p.name.indexOf(searchName)!=-1); // fPersons= persons.filter(p=>true); 表示不进行过滤
if(dataType!=0){
fPersons.sort(function (p1,p2) {
//如果返回负数p1在前,返回正数 p2 在前
if(dataType==2){
return p2.age-p1.age;
}else{
return p1.age-p2.age;
}
})
} // indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
return fPersons; //p相当于是persons =》后面的相当于是匿名函数
}
},
methods: {
setOrderType(type) {
this.dataType = type;
},
}
})
</script>
</body>
</html>
该target属性可以是为事件注册的元素或其后代。它往往是比较有用event.target到this,以确定事件是否正在由于事件冒泡处理。当事件冒泡时,此属性在事件委托中非常有用。
stopPropagation()的用法;
@click.stop和event.stopPropagation()的用法是一样的 阻止单击事件继续传播
@click.prevent:
阻止事件的默认行为
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件处理</title>
</head>
<body>
<div id="dome">
<h2> 1.绑定监听</h2>
<button type="button" @click="test1">test1</button>
<button type="button" @click="test2('tjktjktjk')">test2</button>
<button type="button" @click="test3">test3</button>
<button type="button" @click="test4('123',$event)">test4</button>
<h2> 2. 事件修饰器</h2>
<div style="width:200px;height: 200px;background: #00FF00" @click="test5">
<div style="width:100px;height: 100px;background: #FFFF00 " @click.stop="test6">
</div>
</div>
<a href="www.baidu.com" @click="test7">阻止默认事件触发</a>
<h2> 3.按键修饰器</h2>
<input type="text" @keyup="test8">
<input type="text" @keyup.enter="test8">
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el:"#dome",
data:{
},
methods: {
test1() {
alert("test1");
},
test2(msg) {
alert(msg);
},
test3(event) {
alert(event.target.innerHTML);
},
test4(a, b) {
alert(a + '----' + b.target.innerHTML);
},
test5() {
alert("点击了外面");
},
test6() {
//event.stopPropagation();
alert("点击了里面");
},
test7() {
alert("这就行了");
},
test8(event){
alert(event.target.value+"event.code:"+event.keyCode);
}
}
})
</script>
</body>
</html>
完整的key press 过程分为两个部分,按键被按下,然后按键被松开并复位。
当按钮被松开时,发生 keyup 事件。它发生在当前获得焦点的元素上。
keyup() 方法触发 keyup 事件,或规定当发生 keyup 事件时运行的函数
主要还是用的 v-mode=““
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自动收集</title>
</head>
<body>
<div id="dome">
<form action="" @submit="handSubmit">
<span> 用户名:</span>
<input type="text" v-model="username"><br>
<span> 密码:</span>
<input type="password" v-model="pwd"><br>
<span>性别</span>
<input type="radio" id="female" value="女" v-model="sex" >
<label for="female" >女</label>
<input type="radio" id="male" value="男" v-model="sex" >
<label for="male" >男</label><br>
<span>爱好;</span>
<input type="checkbox" id="basket" value="basket" v-model="likes">
<label for="basket" >篮球</label>
<input type="checkbox" id="foot" value="foot" v-model="likes">
<label for="foot" >足球</label>
<input type="checkbox" id="pingpang" value="pingpang" v-model="likes" >
<label for="pingpang" >乒乓球</label><br>
<span>城市</span>
<select v-model="cityId">
<option >未选择</option>
<option :value="city.id" v-for="(city,index) in allCitys" :key="index"><!--//添加: 是因为不加的时候相当于是一个字符串-->
{
{
city.name}}
</option>
</select><br>
<span>介绍</span>
<textarea rows="10" v-model="desc"></textarea ><br>
<input type="submit" value="提交">
</form>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el:"#dome",
data:{
username:"",
pwd:'',
sex:'男',
likes:['foot'],
allCitys:[{
id:1,name:'渭南'},{
id:2,name:'西安'},{
id:3,name:'韩城'}],
cityId:"3",
desc:"aaab",
},
methods:{
handSubmit(){
alert(this.username+"---"+this.pwd+"---"+this.sex+"---"+this.likes+"---"+this.cityId+"---"+this.desc);
}
}
})
</script>
</body>
</html>
实例的生命周期有三个阶段:初始化显示 更新显示 死亡
生命周期的回调函数 也叫做 钩子函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>生命周期</title>
</head>
<body>
<div id="test">
<button @click="vmDeatory" >destory Vue</button>
<p v-show="isShow"> 我骄傲 </p>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el:"#test",
data:{
isShow:true,
},
methods:{
vmDeatory(){
//干掉vm
this.$destroy();
}
},
mounted(){
//初始化显示之后立即调用(1次)
//循环定时器
this.intervalId=setInterval(()=>{
this.isShow=!this.isShow;//只要是回调函数就使用箭头函数 箭头函数没有内置对象 不存在自己的this
},1000);
},
//死亡前的回调函数 1次
beforeDestroy(){
console.log("--");
clearInterval(this.intervalId)
},
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>生命周期</title>
</head>
<body>
<div id="test">
<button @click="vmDeatory" >destory Vue</button>
<p v-show="isShow"> 我骄傲 </p>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
var vm=new Vue({
el:"#test",
data:{
isShow:true,
},
methods:{
vmDeatory(){
//干掉vm
this.$destroy();
}
},
//初始化阶段
beforeCreate(){
console.log("beforeCreate");
},
created(){
console.log("created");
},
beforeMount(){
("beforeMount");
},
mounted(){
//初始化显示之后立即调用(1次)
//循环定时器
this.intervalId=setInterval(()=>{
this.isShow=!this.isShow;//只要是回调函数就使用箭头函数 箭头函数没有内置对象 不存在自己的this
},1000);
},
//更新阶段
beforeUpdate(){
console.log("beforeUpdate");
},
updated(){
console.log("updated");
},
//死亡前的回调函数 1次
beforeDestroy(){
console.log("beforeDestroy");
clearInterval(this.intervalId)
},
destroyed(){
console.log("destroyed");
}
})
</script>
</body>
</html>
常用的mounted():发送ajax 请求,启动定时器等任务
beforeDestory():做收尾工作:如:清除定时器
(1).操作css的trasition或animation
(2).vue会给目标元素添加/移除特定的class
(3).过度的相关类名
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>动画</title>
<style>
/* 显示、隐藏的过度效guo*/
.xxx-enter-active, .xxx-leave-active {
transition: opacity 1s;
}
/* !* 隐藏时的样式*!*/
.xxx-enter, .xxx-leave-to{
opacity: 0;
}
/* 显示的过度效guo*/
.yyy-enter-active{
transition: all 3s;
}
/* 隐藏的过渡效果*/
.yyy-leave-active{
transition: all 5s;
}
/* !* 隐藏时的样式*!*/
.yyy-enter,.yyy-leave-to{
opacity: 0; /*设置元素的不透明级别*/
transform: translateX(20px);/*向 右移动20px后消失*/
}
</style>
</head>
<body>
<div id="test">
<button @click="isShow=!isShow" >toggle</button>
<transition name="xxx">
<p v-show="isShow"> 我骄傲 </p>
</transition>
</div>
<div id="test2">
<button @click="isShow=!isShow" >toggle2</button>
<transition name="yyy">
<p v-show="isShow"> 我骄傲2 </p>
</transition>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el:"#test",
data() {
return {
isShow:true,
}
}
})
new Vue({
el:"#test2",
data() {
return {
isShow:true,
}
}
})
</script>
</body>
</html>
首先将要过渡的元素用transition包裹,并设置过渡的name
v:text: | 更新元素的 textContent |
v-html: | 更新元素的 innerHTML |
v-if: | 如果为 true, 当前标签才会输出到页面 |
v-else: | 如果为 false, 当前标签才会输出到页面 |
v-show: | 通过控制 display 样式来控制显示/隐藏 |
v-for: | 遍历数组/对象 |
v-on: | 绑定事件监听, 一般简写为@ |
v-bind: | 强制绑定解析表达式, 可以省略 v-bind |
v-model: | 双向数据绑定 |
ref: | 指定唯一标识,vue 对象通过$els 属性访问这个元素对象 |
v-cloak: | 防止闪现, 与 css 配合:[v-cloak]{display:none} |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>指令</title>
<style>
[v-cloak]{
display: none;
}
</style>
</head>
<body>
<div id="test">
<p ref="content">什么,你看见我了 </p>
<button @click="hint">点一下</button>
<p>{
{
msg}}</p>
<p v-text="msg" v-cloak=""></p>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el:"#test",
data: {
msg:'tjk',
},
methods:{
hint(){
alert(this.$refs.content.textContent);
}
}
})
</script>
</body>
</html>
纠错 上面的闪光 叫闪屏就是页面没有加载完首先出来{ {msg}}
如下:
npm install -g vue-cli
vue init webpack vue_demo
cd vue_demo
npm install
npm run dev
访问:http://localhost:8080/
github点击下载:
node.js点击下载
vue - cli的卸载命令 npm uninstall vue-cli -g
接下来这一步可能会报错又
如果爆出权限不够,可以点击菜单然后选择cmd 以管理员方式运行即可
npm install 的作用:
run dev
打开项目后可以在ws的Terminal平台上进行项目运行 如果输入npm run dev 出现“不是内部或者。。。命令”可以查看一下ws的setting中Node.js是否配置了node 如果配置完成后,重新启动项目还是不行 那么试试以管理员方式运行
/*入口js:: 创建Vue实例*/
import Vue from 'vue' // 导包
import App from './App.vue' // 导包
new Vue({
el:'#app',
components:{
App
}, // 将组件映射成为指定名称的标签,相当于{App:App}
template:' ' // 模板插入到el所用
})
<!--根组件-->
<template>
<div>
<img class="logo" src="./assets/2.jpg"/>
<HelloWorld/>
</div>
</template>
<script>
//1. 引入组件
import HelloWorld from './components/HelloWorld.vue'
export default {
/*2. 映射组件标签*/
components:{
HelloWorld
}
}
</script>
<style>
.logo{
width: 500px;
height: 800px;
}
</style>
<template>
<div>
<p class="msg">{
{
msg}}</p>
</div>
</template>
<script>
export default {
//配置对象与Vue一致
data(){
//data可以写对象也可以写函数,但是在组件中必须写函数
return{
msg:"Hello Vue Component"
}
}
}
</script>
<style>
.msg{
color:black;
font-size: 30px;
}
</style>
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>vuedome</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
template:是使用组件标签
main.js中的el 元素指的是 index.html中的id
Props
/*
创建vue实例
*/
import Vue from 'vue'
import App from './App.vue'
new Vue({
el:'#app',/*这里需要和index界面的div的id一样*/
components:{
/*相当于是注册组件*/
App
},
template:' '//使用组件
})
App.vue
<template>
<div>
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>请发表对kunkun的评论</h1>
</div>
</div>
</div>
</header>
<div class="container">
<Add :addComment="addComment"/><!--将此方法传递给子组件-->
<list :comments="comments"/>
</div>
</div>
</template>
<script>
import Add from './components/Add.vue'
import List from './components/List.vue'
export default {
data(){
return {
comments:[ /*组件间的相互通信最好同名 数据在那个组件,更新数据的行为就在那个组件*/
{
name:"张菁",
content:"偶有还不错哦哦"
},{
name:"张十八",
content:"张菁说得对"
},{
name:"宋十五",
content:"滑行吧"
}
]
}
},
methods:{
addComment(comment){
this.comments.unshift(comment);
}
},
components:{
Add,
List
}
}
</script>
<style>
</style>
add.vue
<template>
<div class="col-md-4">
<form class="form-horizontal">
<div class="form-group">
<label>用户名</label>
<input type="text" class="form-control" placeholder="用户名" v-model="name"><!--自动收集数据 <input v-model="data" />-->
</div>
<div class="form-group">
<label>评论内容</label>
<textarea class="form-control" rows="6" placeholder="评论内容" v-model="content"></textarea>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-default pull-right" @click="add">提交</button>
</div>
</div>
</form>
</div>
</template>
<script>
export default {
props:{
addComment:{
/*要求指定的东西有属性名、属性值的类型和必要性*/
type:Function,
required:true,
}
},
data(){
return{
name:'',
content:''
}
},
methods:{
add (){
/*检查输入的合法性*/
const name=this.name.trim();
const content=this.content.trim();
if(!name||!content){
alert("为写入数据");
return null;
}
/*根据输入的数据,封装成comment对象*/
const comment={
name,
content
}
/*添加到comments对象中*/
this.addComment(comment);
/*清除输入*/
this.name='';
this.content='';
}
}
}
</script>
<style>
</style>
list.vue
<template>
<div class="container">
<div class="col-md-8">
<h3 class="reply">评论回复:</h3>
<h2 style='display: none'>暂无评论,点击左侧添加评论!!!</h2>
<ul class="list-group">
<Item v-for="(comment,index) in comments" :key="index" :comment="comment"/>
</ul>
</div>
</div>
</template>
<script>
import Item from './Item'
export default {
/*声明接受属性 这个属性就会成为组件对象的属性 模板中可以直接使用*/
props:['comments'],
components:{
Item
}
}
</script>
<style>
.reply {
margin-top: 0px;
}
</style>
item.vue
<template>
<div>
<li class="list-group-item">
<div class="handle">
<a href="javascript:;">删除</a>
</div>
<p class="user"><span >{
{
comment.name}}</span><span>说:</span></p>
<p class="centence">{
{
comment.content}}</p>
</li>
</div>
</template>
<script>
export default {
props:{
/*指定属性名和属性值类型*/
comment:Object
}
}
</script>
<style>
li {
transition: .5s;
overflow: hidden;
}
.handle {
width: 40px;
border: 1px solid #ccc;
background: #fff;
position: absolute;
right: 10px;
top: 1px;
text-align: center;
}
.handle a {
display: block;
text-decoration: none;
}
.list-group-item .centence {
padding: 0px 50px;
}
.user {
font-size: 22px;
}
</style>
App.vue
<template>
<div class="todo-container">
<div class="todo-wrap">
<!--上-->
<TodoHeader :addTodo="addTodo" />
<!--中-->
<TodoList :todos="todos" :delTodo="delTodo"/>
<!--下-->
<TodoFooter :todos="todos" :deleteCompleteTodos="deleteCompleteTodos" :selectAllTodos="selectAllTodos"/>
</div>
</div>
</template>
<script>
import TodoHeader from './components/TodoHeader.vue'
import TodoFooter from './components/TodoFooter.vue'
import TodoList from './components/TodoList.vue'
export default {
data(){
return {
todos:[
{
tittle:"吃饭",complete:false},
{
tittle:"睡觉",complete:true},
{
tittle:"打豆豆",complete:false}
]
}
},
methods:{
/*添加todo*/
addTodo(todo){
this.todos.unshift(todo);
},
/*删除选中的todo*/
delTodo(index){
this.todos.splice(index,1);
},
/*
删除所有选中的todo
*/
deleteCompleteTodos(){
this.todos=this.todos.filter(todo=>!todo.complete);
},
/*全选或者全部选*/
selectAllTodos(isCheck){
this.todos.forEach(todo=>todo.complete=isCheck);
}
},
components:{
TodoHeader,TodoFooter,TodoList
},
}
</script>
<style>
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
TodoList.vue
<template>
<ul class="todo-main">
<TodoItem v-for="(todo,index) in todos " :key="index" :todo="todo" :index="index" :delTodo="delTodo"/>
</ul>
</template>
<script>
import TodoItem from './TodoItem.vue'
export default {
components:{
TodoItem
},
props:{
todos:Array,
delTodo:Function
}
}
</script>
<style>
.todo-main {
margin-left: 0px;
border: 1px solid #ddd;
border-radius: 2px;
padding: 0px;
}
.todo-empty {
height: 40px;
line-height: 40px;
border: 1px solid #ddd;
border-radius: 2px;
padding-left: 5px;
margin-top: 10px;
}
/*item*/
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}
li label {
float: left;
cursor: pointer;
}
li label li input {
vertical-align: middle;
margin-right: 6px;
position: relative;
top: -1px;
}
li button {
float: right;
display: none;
margin-top: 3px;
}
li:before {
content: initial;
}
li:last-child {
border-bottom: none;
}
</style>
TodoItem.vue
<template>
<div>
<!-- 进入内部元素 以后onmouseout会执行 出内部元素 onmouseover 会执行
<li onmouseenter="" onmouseleave="" onmouseover="" onmouseout="">-->
<li @mouseenter="handleShow(true)" @mouseleave="handleShow(false)" :style="{background: bgColor}">
<label>
<input type="checkbox" v-model="todo.complete"/>
<span>{
{
todo.tittle}}</span>
</label>
<button class="btn btn-danger" v-show="isShow" @click="deleteItem">删除</button>
</li>
</div>
</template>
<script>
export default {
props: {
todo: Object,
index: Number,
delTodo:Function
},
data(){
return{
bgColor:'white',/*默认的背景颜色*/
isShow:false /*按钮是否展示*/
}
},
methods:{
handleShow(bool){
if(bool){
this.bgColor="#aaaaaa",
this.isShow=true
}else{
this.bgColor="white",
this.isShow=false
}
},
deleteItem(){
const {
todo,index,delTodo}=this;
var result=todo.tittle;
if(window.confirm('确认删除'+result+'吗?')){
delTodo(index);
}
}
}
}
</script>
<style>
</style>
TodoHeader.vue
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="tittle" @keyup.enter="addItem"/>
</div>
</template>
<script>
export default {
props:{
addTodo:{
type:Function,
required:true
}
},
data(){
return {
tittle:''
}
},
methods:{
addItem(){
/* 1.检查输入的合法性*/
const tittle=this.tittle.trim();
if(!tittle){
alert("请您输入信息后在进行提交");
return null;
}
/*2. 根据输入生成一个todo对象*/
const todo={
tittle,
complete:false
}
/*3. 添加到todos数组中*/
this.addTodo(todo);
/*4. 清除输入*/
this.tittle='';
}
}
}
</script>
<style>
.todo-header input {
width: 560px;
height: 28px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px 7px;
}
.todo-header input:focus {
outline: none;
border-color: rgba(82, 168, 236, 0.8);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}
</style>
TodoFooter.vue
<template>
<div class="todo-footer">
<label>
<input type="checkbox" v-model="isAllCheck"/>
</label>
<span>
<span>已完成{
{
completeSize}}</span> / 全部{
{
todos.length}}
</span>
<button class="btn btn-danger" v-show="completeSize" @click="deleteCompleteTodos">清除已完成任务</button>
</div>
</template>
<script>
export default {
props: {
todos: Array,
deleteCompleteTodos: Function,
selectAllTodos: Function
},
computed:{
completeSize(){
return this.todos.reduce((preTotal,todo)=>preTotal+(todo.complete?1:0),0);
},
isAllCheck:{
get(){
return this.completeSize==this.todos.length && this.completeSize>0;
},
set(vlaue){
/*vlaue是当前checkbox最新的值*/
this.selectAllTodos(value);
}
}
}
}
</script>
<style>
.todo-footer {
height: 40px;
line-height: 40px;
padding-left: 6px;
margin-top: 5px;
}
.todo-footer label {
display: inline-block;
margin-right: 20px;
cursor: pointer;
}
.todo-footer label input {
position: relative;
top: -1px;
vertical-align: middle;
margin-right: 5px;
}
.todo-footer button {
float: right;
margin-top: 5px;
}
</style>
注意:
将浏览器上输入数据的结果以文件的形式保存在电脑上。
父组件可以在使用子组件的地方直接使用v-on来监听子组件触发的事件
不能用$on监听子组件释放事件,而必须在模板里直接用v-on绑定
父组件:
子组件
注意: 这种方式只能在父子组件之间传递
此方法用来代替函数属性
//下载
npm install --save pubsub-js
//查看版本信息
npm info pubsub-js
注意:
//订阅消息
PubSub.subscribe('delTodo',(msg,index) =>{
//这个msg相当于是前面的函数名 index相当于是函数的参数
this.delTodo(index);
})
// 用了箭头函数相当取消本函数内的this对象,要找this只能在外面找
//发布消息
PubSub.publish('delTodo',index);
//第一个参数是调用的函数名,第二个参数是给函数传递的参数
消息的订阅与发布:好处是组件间传递信息时没有关系限制,父子 祖孙 或者兄弟之间皆可
此方法用于父组件向子组件传递‘标签数据’
1. 此方法只能传递标签,不可以进行数据及参数的传递
2. 此方法中所有标签属性用到的函数方法及参数需要在父组件中
vue插件 非官方库
通用的ajax请求库,官方推荐
<template>
<div>
<div v-if="!repoUrl">Loading!!!</div>
<div v-else="repoUrl">most star repo is <a :href="repoUrl">{
{
repoName}}</a></div>
</div>
</template>
<script>
export default {
data(){
return{
repoUrl:'',
repoName:''
}
},
mounted(){
//发送ajax请求获取数据 https://api.github.com/search/repositories?q=v&sort=stars
const url='https://api.github.com/search/repositories?q=v&sort=stars';
this.$http.get(url).then(
response=>{
const result=response.data;
//得到最受欢迎的repo
const mostRepo=result.items[0];
this.repoUrl=mostRepo.html_url;
this.repoName=mostRepo.name;
}, reponse=>{
alert("请求失败");
})
}
}
</script>
<style>
</style>
<template>
<div>
<div v-if="!repoUrl">Loading!!!</div>
<div v-else="repoUrl">most star repo is <a :href="repoUrl">{
{
repoName}}</a></div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data(){
return{
repoUrl:'',
repoName:''
}
},
mounted(){
//发送ajax请求获取数据 https://api.github.com/search/repositories?q=v&sort=stars
const url='https://api.github.com/search/repositories?q=v&sort=stars';
//使用axios发送ajax请求
axios.get(url).then( response=>{
const result=response.data;
//得到最受欢迎的repo
const mostRepo=result.items[0];
this.repoUrl=mostRepo.html_url;
this.repoName=mostRepo.name;
}).catch(error=>{
alert("失败了");
})
}
}
</script>
<style>
</style>
<template>
<div id="app">
<div class="container">
<Search/>
<UserMain/>
</div>
</div>
</template>
<script>
import Search from './compontents/Search.vue'
import Main from './compontents/Main.vue'
export default {
components:{
Search,
UserMain:Main /*可以起别名*/
}
}
</script>
<style>
</style>
<template>
<section class="jumbotron">
<h3 class="jumbotron-heading">Search Github Users</h3>
<div>
<input type="text" placeholder="enter the name you search" v-model="searchName"/>
<button @click="search">Search</button>
</div>
</section>
</template>
<script>
import PubSub from 'pubsub-js'
export default {
data(){
return {
searchName:''
}
},
methods:{
search(){
const searchName=this.searchName.trim();
if(searchName){
//发布搜索的消息
PubSub.publish('search',searchName);
alert(searchName);
}
}
}
}
</script>
<style>
</style>
<template>
<div>
<h2 v-if="firstView">输入用户名搜索</h2>
<h2 v-else-if="loading">LOADING...</h2>
<h2 v-else-if="errorMsg">{
{
errorMsg}}</h2>
<div class="row">
<div class="card" v-for="(user,index) in users" :key="index">
<a :href="user.url" target="_blank">
<img :src="user.avatarUrl" style='width: 100px'/>
</a>
<p class="card-text">{
{
user.name}}</p>
</div>
</div>
</div>
</template>
<script>
import PubSub from 'pubsub-js'
import axios from 'axios'
export default {
data(){
return {
firstView:true,
loading:false,
users:null, /*{url avatar_url name}*/
errorMsg:''
}
},
mounted(){
//是否在此发ajax请求 不是,而是在点击search之后
//订阅搜索的消息
PubSub.subscribe('search',(msg,searchName)=>{
//说明需要发ajax请求进行搜索
//更新状态(请求中的状态)
this.firstView=false,
this.loading=true,
this.users=[],
this.errorMsg=''
//发ajax请求
const url=`https://api.github.com/search/users?q=${
searchName}`
axios.get(url).then(response=>{
const result=response.data;
const users=result.items.map(item=>({
url:item.html_url,
avatarUrl:item.avatar_url,
name:item.login,
}));
//成功,更新成功的状态
this.users=users;
this.loading=false;
}).catch(error=>{
//失败
this.loading=false;
this.errorMsg="请求失败";
})
})
}
}
</script>
<style>
.card {
float: left;
width: 33.333%;
padding: .75rem;
margin-bottom: 2rem;
border: 1px solid #efefef;
text-align: center;
}
.card > img {
margin-bottom: .75rem;
border-radius: 100px;
}
.card-text {
font-size: 85%;
}
</style>
通过 Vue.js 可以实现多视图的单页Web应用
路由的含义:
一种映射关系 key–value
key:path
value:处理请求的回调函数(后台路由);组件(前台路由)
下载:npm install vue-router --save
1. <router-link>: 用来生成路由链接
<router-link to="/xxx">Go to XXX</router-link>
2. <router-view>: 用来显示当前路由组件界面
<router-view></router-view>
使用路由的基本步骤:
import Vue from 'vue'
import App from './App.vue'
import router from './router' /*默认暴露可以用任何名字*/
new Vue({
//配置对象的属性名都是一些确定的名称,不能随便修改
el:'#app',
components:{
App},
template:' ',
router
})
<template>
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>Router Test</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
<!--生成路由链接-->
<router-link to="/about" class="list-group-item">About</router-link>
<router-link to="/home" class="list-group-item">Home</router-link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
<!--显示当前组件-->
<router-view ></router-view>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
/*
* 路由器模块
* */
import Vue from 'vue'
import VueRouter from 'vue-router'
import About from '../views/About.vue'
import Home from '../views/Home.vue'
import News from '../views/News.vue'
import Message from '../views/Message.vue'
Vue.use(VueRouter);
export default new VueRouter({
//n个路由
routes: [
{
path: '/about',
component: About,
},
{
path: '/home',
component: Home,
children:[
{
/*path:'/News',// path最左侧的/永远代表跟路由 直接写/News不对
*/
path:'/home/News',
/*path:'News', 简化写法*/
component:News,
},
{
path:'Message',
component:Message
},
{
path:'',
redirect:'News'
}
]
},
{
path:'/',
redirect:'/about'
}
]
})
path:'/News',// path最左侧的/永远代表跟路由 直接写/News不对
path:'News', 简化写法 代表本级目录下的文件
是什么:
编码实现:
<keep-alive>
<router-view></router-view>
</keep-alive>
children:[{
path:'/home/message/detail/:id',
component:MessageDetail
}]
(2). 路由路径:
<li v-for="(message,index) in messages" :key="message.id" >
<router-link :to="`/home/message/detail/${message.id}`"> <a >{
{
message.tittle}}</a></router-link>
</li>
(3) 路由组件中读取请求参数
this.$route.params.id
index.js
/*
* 路由器模块
* */
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Message from '../views/Message.vue'
import MessageDetail from '../views/MessageDetail.vue'
Vue.use(VueRouter);
export default new VueRouter({
//n个路由
routes: [
{
path: '/home',
component: Home,
children:[
{
path:'/home/News',
component:News,
},
{
path:'Message',
component:Message,
children:[ 重点:
path:'/home/message/detail/:id',
component:MessageDetail
}]
}
]
}
]
})
message.vue
<template>
<div>
<ul>
<li v-for="(message,index) in messages" :key="message.id" >
<router-link :to="`/home/message/detail/${message.id}`"> <a >{
{
message.tittle}}</a></router-link> //注意符号``
</li>
</ul>
<router-view></router-view>
</div>
</template>
<script>
export default {
data(){
return{
messages:[]
}
},
mounted(){
//模拟ajax请求从后台获取数据
setTimeout(()=>{
const messages=[{
id:1,
tittle:'message001',
},
{
id:2,
tittle:'message002',
},
{
id:3,
tittle:'message003'
}
]
this.messages=messages;
},1000);
}
}
</script>
<style>
</style>
MessageDetail.vue:
<template>
<div>
<ul>
<p>ID:{
{
$route.params.id}}</p>
<li>id:{
{
messageDetail.id}}</li>
<li>tittle:{
{
messageDetail.tittle}}</li>
<li>content:{
{
messageDetail.content}}</li>
</ul>
</div>
</template>
<script>
export default {
data(){
return {
messageDetail:{
},
}
},
mounted(){
setTimeout(()=>{
const allMessageDetails=[{
id:1,
tittle:'message001',
content:"massage001Content"
},
{
id:2,
tittle:'message002',
content:"massage002Content"
},
{
id:3,
tittle:'message003',
content:"massage003Content"
}];
this.allMessageDetails=allMessageDetails;
const id=(this.$route.params.id)*1; this.messageDetail=allMessageDetails.find(detail=>detail.id===id) //filter 过滤产生的数据类型是数组类型的
//find 查找满足条件的某一个
},1000)
},
watch:{
//点击路由连发生改变后,进行修改
$route:function (value) {
//路由路径发生改变
const id=(value.params.id)*1;
this.messageDetail=this.allMessageDetails.find(detail=>detail.id===id)
}
}
}
</script>
<style>
</style>
栈的结构进行
相关 API :
1) this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
2) this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
3) this.$router.back(): 请求(返回)上一个记录路由
4) this.$router.go(-1): 请求(返回)上一个记录路由
5) this.$router.go(1): 请求下一个记录路由
<template>
<div>
<ul>
<li v-for="(message,index) in messages" :key="message.id" >
<router-link :to="`/home/message/detail/${message.id}`"> <a >{
{
message.tittle}}</a></router-link>
<button @click="pushShow(message.id)">push查看</button>
<button @click="replaceShow(message.id)">replace查看</button>
</li>
</ul>
<button @click="$router.back()">回退</button>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
data(){
return{
messages:[]
}
},
mounted(){
//模拟ajax请求从后台获取数据
setTimeout(()=>{
const messages=[{
id:1,
tittle:'message001',
},
{
id:2,
tittle:'message002',
},
{
id:3,
tittle:'message003'
}
]
this.messages=messages;
},1000);
},
methods:{
pushShow(id){
this.$router.push(`/home/message/detail/${
id}`)
},
replaceShow(id){
this.$router.replace(`/home/message/detail/${
id}`)
}
}
}
</script>
<style>
</style>