一、从Hello World说起
<body>
<div id="box">
{{10+20}}
<p>{{myname}}</p>
</div>
<div>
{{10+20}}
</div>
</body>
<script>
var a = new Vue({
el: "#box", //确定Vue渲染部位
data: {
myname: "zzh"
} //状态
})
</script>
执行结果如下:
30 //vue渲染部位可执行运算
zzh //vue渲染部位可执行变量替换,且变量a.myname可以简单获取
{10+20}} //未渲染部位
二、Vue基础语法
1.文本
{{ 代码段 }} //双大括号内部代码作为JS代码执行。
{{ 10>20? 'aaa':'bbb' }} //双大括号内部不加引号部分会被视为变量
{{<b>test</b>}} //原样输出,不支持直接渲染带标签文本
<div v-html="<b>test</b>" //输出加粗test,v-html为指令
2.写入html指令
<div v-html="myhtml"></div>
data: { myhtml:"<a href='http://www.baidu.com'>1</a>"}
3.动态显示和隐藏指令
<div v-show="isShow">动态显示和隐藏</div>
data: {isShow:true} //状态
4.动态创建和删除指令
<div v-if="isCreated">动态创建和删除</div>
data: {isCreated:true} //状态
5.动态绑定Class
1.三目控制
<div :class="isActive?'red':'yellow'">动态绑定Class</div>
<button @click="changeActive()">changeActive</button>
methods:{
changeActive(){
this.isActive = !this.isActive
}
2.对象写法
<div :class="classObj">对象绑定Class</div>
data: {
classObj:{
className_1:true,
className_2:true
}
}//只限于className_1,2,无法新增className_3
如要新增,使用 Vue.set(a.classObj , "className_3" ,true)实现,原因在后面讲到
3.数组写法
<div :class="classArr">数组绑定Class</div>
data: {
classArr:["className_1","className_2"]
}//利用classArr.pop()、classArr.push("className_3")删除或者新增
6.条件渲染(v-if,v-else,v-for)
1.单分支
<button @click="addGoods()">addGoods</button>
<ul v-if="datalist.length">
<li v-for="data in datalist">
{{data}}
</li>
</ul>
<div v-else>购物车什么也没有0-0~</div>
data:{
datalist:[]
}
methods:{
addGoods(){
this.datalist=["小米10","电视机","机顶盒"]
}
}
2.多分支
<div v-if="which===1"> 这是分支1</div>
<div v-else-if="which===2">这是分支2</div>
<div v-else=> 这是分支3</div>
data:{
which:1
}
7.列表渲染
1.数组列表渲染
<ul>
<li v-for="(data,index) in dataArr">
{{index}}--> {{data}}
</li>
</ul>
data: {
dataArr:["first","second","third"]
} //数组列表渲染,可使用push()\pop()修改
使用 push() , pop() , shift() , unshift() , splice() , sort() , reverse() 操作数组后,会影响原数组,vue会动态检测变动
使用 filter() , concat() , slice() , map() 操作数组后,不会影响原数组,vue也就无法检测变动,可以用重赋值方式,改变原数组,使得变动被检测. 如 : a.datalist = a.datalist.concat(["5","6"])//拼接数组
特殊的:通过索引直接改变数组值,原数组会受到影响,但不会动态检测变动.
扫描二维码关注公众号,回复: 9284911 查看本文章需通过:Vue.set(a.datalist , 2 , "我是重写的")// 2为需要修改的数组值索引
2.对象列表渲染
<ul >
<li v-for="(data,key) in obj">
{{key}}--> {{data}}
</li>
</ul>
data:{
obj:{
name:"zzh",
age:23,
addr:"河北"
}
} //对象列表渲染
v-for中的 (data,key) in obj 可换成 data in obj 或者 (data,key) of obj
v-for中使用 (data,key) in obj 可改成 v-for="(data,key) in obj" :key="data.id" ,避免部分重复渲染,增强用户体验
3.动态模糊查询
<input type="text" @input="change()" v-model="mytext"/>
<ul >
<li v-for="data in dataArr_liebiao">
{{data}}
</li>
</ul>
data:{
mytext:'',
dataArr_liebiao:
["aaa","aab","abc","bbc","ccd","acd","add","bcd"],
dataArr_beifen:
["aaa","aab","abc","bbc","ccd","acd","add","bcd"]
},
methods:{change(){
var showList = this.dataArr_beifen.filter(item=>item.indexOf(this.mytext)>-1);
this.dataArr_liebiao = showList;
}
}
4.事件修饰符
- 阻止冒泡(.stop)
<ul @click = "click_ul()">
<li @click.stop = "click_li()">按钮1</li>
<li>按钮2</li>
<li>按钮3</li>
</ul>
methods:{
click_ul(){
console.log("点击了UL");
},
click_li(){
console.log("点击了LI");
}
}
- 阻止默认行为(.prevent)
<a href="http://www.baidu.com" @click.prevent="changePage()">阻止跳转百度</a>
- 只接受自己被点击事件(.self)
<ul @click.self = "click_ul()">
<li @click= "click_li()">按钮1</li>
</ul>
methods:{
click_ul(){
console.log("点击了UL");
},
click_li(){
console.log("点击了LI");
}
}
相当于忽略了点击孩子事件的冒泡
- 只触发一次(.once)
<ul>
<li @click.once = "click_li()">一次性按钮</li>
</ul>
methods:{
click_li(){
console.log("点击了LI 1次");
}
}
5.按键修饰符
- 判断某键按下时执行
<input type="text" @keyup.enter="present()">
或<input type="text" @keyup.13="present()">
methods:{
present(){
console.log("提交留言");
}
} //@keyup.键值可以匹配任何键
原生JS利用@keyup加判断也可以实现,得到键值,如下:
<input type="text" @keyup = "present($event)">
methods:{
present(ev){
if(ev.keycode==13){
console.log("提交留言");
}
}
}//13是enter的键值,用ev.keycode可以得到按下按键的键值
8.表单控件绑定
1.双向数据绑定,文本[文本框]
<input type="text" v-model="dynamic_text">{{dynamic_text}}
data:{
dynamic_text:"我是动态改变的"
}
<textarea cols="10" rows="3" v-model="dynamic_text"></textarea>
data:{
dynamic_text:"我是动态改变的"
}
2.双向数据绑定,布尔值[单选框]
<input type="checkbox" v-model="isChecked">记住用户名--{{isChecked}}
data:{
isChecked:true
}
3.双向数据绑定,数组[多选框]
<input type="checkbox" v-model="checkGrop" value="游泳">游泳
<input type="checkbox" v-model="checkGrop" value="唱歌">唱歌
<input type="checkbox" v-model="checkGrop" value="跳舞">跳舞
{{checkGrop}}
data:{
checkGrop:[]
}
4.双向数据绑定,字符串[单选radio]
<input type="radio" v-model="checkRadio" value="PHP">PHP
<input type="radio" v-model="checkRadio" value="C#">C#
<input type="radio" v-model="checkRadio" value="JS">JS
{{checkRadio}}
data:{
checkRadio:""
}
小实验,模拟求购物车选中商品总价
<input type="checkbox" v-model="checkAll" @change="check_All()">全选
<ul>
<li v-for="data in shopCart">
<input type="checkbox" v-model="shopGrop" :value="data" @change="change_li()"> {{data}}
</li>
</ul>
商品总价格:{{total_price()}}
data:{
shopGrop:[], //双向绑定获得用户选中商品
checkAll:false,
shopCart:[
{
name:"商品一",
price:10,
num:2,
id:1
},
{
name:"商品二",
price:15,
num:4,
id:2
},
{
name:"商品三",
price:30,
num:1,
id:3
},
]
}
methods:{
check_All(){
if(this.checkAll){
this.shopGrop=this.shopCart;
}else{
this.shopGrop=[];
}
}, //当选中全选框时,checkAll为true
change_li(){
if(this.shopGrop.length==this.shopCart.length)
{
this.checkAll=true;
}else{
this.checkAll=false;
}
},//判断当选项全选或不是全选时,自动使全选框变化
total_price(){
var sum=0;
this.shopGrop.forEach(element => {
sum+=element.price*element.num;
});
return sum
}
}
5.表单修饰符
- v-model.lazy
<input type="text" v-model.lazy="mytext">{{mytext}}
//只有失去焦点时才同步值
- v-model.number
<input type="number" v-model.number="mynumber">{{mynumber}}
//限定只能输入数字
- v-model.trim
<input type="text" v-model.trim="myusername">{{myusername}}
//去除首尾空格
三、Vue组件
1.fetch 数据请求
fetch("addr.json").then(res=>res.json()).then(res=>{
console.log(res)
//得到的res数据只能向下访问一层,即res.data.content
2.axios 数据请求
axios.get("addr.json").then(res=>{
console.log(res.data.yourdata)
}).catch(err=>{
console.log(err)
})//axios自动包装一个data属性,data内为真实数据(先引入axios才能用)
写个小例子: fetch,axios - - >今日诗词接口
<button @click="getjson()">111</button>
<ul>
<li v-for="data in datalist">
<p>{{data}}<br></p>
</li>
</ul> <!--fetch,axios 操作今日诗词接口-->
methods:{
getjson(){ fetch("https://v2.jinrishici.com/one.json").then(res=>res.json()).then(res=>{
this.datalist=res.data;
})
-----------------或者------------------- axios.get("https://v2.jinrishici.com/one.json").then(res=>{Vue.set(this.datalist,0,res.data.data.content);
Vue.set(this.datalist,1,res.data.data.origin.author) }).catch(err=>{
console.log(err);
})
},
}//切记datalist[0]=?这种方式不会动态渲染
3.compuyed 计算属性
定义像函数,使用像属性(不用括号),计算属性的性能优于普通方法methods,计算属性只会调用一次,结果会缓存,相同值自动匹配
<p>计算属性:{{upper_name}}</p>
data:{
name:"zhangzhihao"
}
computed:{
upper_name(){
return this.name.substring(0,1).toUpperCase() + this.name.substring(1)
}
} //计算属性首字母大写
改造原来写的动态模糊查询
<input type="text" v-model="mytext">
<ul>
<li v-for="data in getDataArr">
{{data}}
</li>
</ul>
computed:{
getDataArr(){returnthis.dataArr.filter(item=>
item.indexOf(this.mytext)>-1)
}
mytext与输入框值动态绑定,当输入值改变时,执行计算属性getDataArr(),返回值作用于v-for,会动态刷新列表,是不是很nice
4.组件化开发
扩展HTML,封装可复用的代码,一个组件可封装dom结构、样式、JS逻辑等
定义组件方式
1.全局定义组件(作用域隔离)
<script>
Vue.component("cpnt_name",{
template:`
<div style="background:yellow">
<button @click="click_left()">左侧</button>
<input type="text" value="哈哈快输入">
<button>右侧</button>
</div>`,
methods:{
click_left(){
console.log("click_lift");
}
}
}) //全局定义组件
</script>
<div>
<cpnt_name></cpnt_name> <!-- 使用全局定义组件-->
</div>
全局组件定义时,使用了 Vue.component(“name”,{ ... ... })形式,全局组件的使用其实是位于根组件中的:
2.局部组件
<script>
Vue.component("cpnt_name",{
template:`
<div style="background:yellow">
<button @click="click_left()">左侧</button>
<input type="text" value="哈哈快输入">
<button>右侧</button>
<child></child>
</div>`,
methods:{
click_left(){
console.log("click_lift");
}
},
components:{
child:{
template:`
<div style="background:green">
<button @click="click_child_left()">左侧</button>
我是cpnt_name的孩子组件~
</div>`,
methods:{
click_child_left(){
console.log("click_child_left");
}
}
}
}
}) //全局定义组件(其中包含了一个child子组件)
</script>
<div>
<cpnt_name></cpnt_name> <!-- 使用全局定义组件-->
</div>
局部组件是包含在某全局组件中的,使用关键字 components:{ child_name:{ ... ... } ... ... }方式
!注意,组件与Vue实例有几点区别
- 自定义组件需要有一个根节点root element
- 父子组件的各种属性方法是无法直接共享的
- 组件中可以有data,methods,computed,但data必须是一个函数,返回值是data 如下:
data(){
return{ data1:"data1" }
}
- 父传子通信(属性向下传)
<div>
<cpnt_name myname="第一个" :myshow="true"></cpnt_name>
<cpnt_name myname="第二个" :myshow="false"></cpnt_name>
<cpnt_name myname="第三个" :myshow="true"></cpnt_name>
</div>
<script>
Vue.component("cpnt_name",{
template:`
<div style="background:yellow">
<button @click="click_left()">左侧</button>
<input type="text" v-show="myshow">{{myname}}
<button>右侧</button>
<child></child>
</div>`,
props:["myname","myshow"]
</script>
props:["myname","myshow"] 父子通信关键,父组件中通过设置"myname","myshow"的值,子组件通过props接受父组件传回值,之后可以在子组件中使用。注意 当传回值需要当作JS语句使用时,父组件要加冒号动态绑定!
将 props 稍加改造,可以对父组件传过来的值进行属性验证:
props:{
myname:String,
myshow:Boolean
}
如果传入类型不符,则会报错,提示应传入类型。
属性验证可选类型:Number,String,Boolean,Array,Object,Function,null(不限类型)。
- 子传父通信(事件向上传)
<body>
<div id="Box">
<child @father_function="my_function($event)"></child>
我是父组件,要子组件状态:{{reserve}}
</div>
</body>
<script>
Vue.component("child",{
template:`
<div>
<input type="button" @click="click_child()" value="子传父">
</div>`,
data(){
return {
state:"良好"
}
},//子组件状态的写法,data必须是函数,返回值为状态
methods:{
click_child(){
this.$emit("father_function",this.state) // this.$emit("父组件自定义的函数名",要传递的值)回调函数
}
}
})//自定义全局组件
var a= new Vue({
el:"#Box",
data:{
reserve:""
},
methods:{
my_function(ev){
console.log(ev);
this. reserve = ev;
}
}//ev接受子组件传来的值
})
</script>
几个重点:当点击子组件中的 button 时,触发子组件中的 click_child()事件,
随后使用 this.\(emit("父组件自定义的函数名",要传递的值)**回调函数寻找父组件中对应函数名,这里是***father_function*** ,而后触发父组件中自定义的函数***my_function(\)event)* ,注意此处的$event为固定写法 ,最后执行函数体 my_function(ev) ,其中的 ev 即子组件要传递的值,随后即可使用该值。
一句话:子组件通过this.$emit()触发父组件方法
- ref通信
1.ref放在标签上,拿到原生节点
<div id="Box">
<input type="text" ref="mytext">
<button @click="myclick()">add</button>
</div>
<script>
var a =new Vue({
el:"#Box",
methods:{
myclick(){
console.log( this.$refs.mytext.value);
}
}
})
</script> //this.$refs.mytext就拿到了输入框
2.ref放在组件上,拿到组件对象
还是上面的例子,加以优化
<div id="Box">
<input type="text" ref="mytext">
<button @click="myclick()">add</button>
<child ref="mychild"></child>
</div>
<script>
Vue.component("child",{
template:`
<div>
我只是个孩子啊0-0
</div>`,
data(){
return {
child_data:"孩子的秘密"
}
}
})
var a =new Vue({
el:"#Box",
methods:{
myclick(){
this.$refs.mytext.value= this.$refs.mychild.child_data
}//抢夺子组件的data
}
})
</script>
通过ref,你甚至直接得到了 this.$refs.mychild 对象!那还不随便搞了,拿啥都行啊,不需要子再去传父了
methods:{
child_speak(){
console.log("听爸爸的话");
}
}//子组件增加一个方法
this.$refs.mychild.child_speak()//父组件完全可直接调用
更进一步,父组件在调用子组件方法时,可以传值给子组件了呀,轻松父传子
methods:{
child_speak(receive){
console.log("听爸爸的话",receive);
}
}
this.$refs.mychild.child_speak("零花钱")//调用并传值