Vue的奇妙世界

一、从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"])//拼接数组

特殊的:通过索引直接改变数组值,原数组会受到影响,但不会动态检测变动.

需通过: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("零花钱")//调用并传值

猜你喜欢

转载自www.cnblogs.com/beibingji/p/12335318.html