关于Vue的一些基础语法

60 阅读2分钟

插值语法(大胡子表达式)

{{ 初始化的值 }}{{ 初始化的值 }}

插值语法只能使用在标签外,不能使用在标签上

插值语法只支持单向绑定功能,可以进行非常简单的业务逻辑

无法实现 迭代 流程控制等,需要搭配指令语法进行更复杂的操作

<div id="app">
    {{message}} //渐进式JavaScript框架
    {{count/10}} //10
    {{flag?'ios':'android'}} //ios
    <!-- 插值语法无法显示 null 和 undefined 什么都不显示 -->
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
    new Vue({
        el:'#app',
        data = {
            /* 这被称之为初始化的值 */
            message: '渐进式JavaScript框架',
            count: 100,
            flag: true,
            text: '123.456.789',
            val1: null,
            val2: undefined,
            value1: '<span style="color:coral">测试</span>',
            mySrc: './assets/logo.png',
            myCss: 'width:100px',
            myStyle: 'background-color:rgb(255,0,255)',
            myFlag: false,
        }
    })
</script>

指令语法

格式:

<tagName v-指令名="绑定的值" />

v-html:向元素中插入超文本,支持标签css等,就相当于js中 innerHTML
v-text:向元素中插入文本,不支持标签 css等,相当于js中的innerText
在前端开发时,为了避免XSS网络攻击,严禁插入 动作
​
<p v-html="value1" style="background-color: pink;"></p>//格式生效
<p v-text="value1" style="background-color: pink;"></p>//显示 <span style="color:coral">测试</span>
​
​
v-once:一次性插值绑定,仅仅实现了一次的单向绑定,之后失效
<div v-once>{{ message }}</div>
​
​
​
v-model:天生支持单双向绑定,只能使用在表单项中,类似之前的value属性值,但是绑定初始化的数据
v-model如果使用在复选框中
     单向绑定:
        如果data初始化的值为真值,则勾选
        为假值则不勾选    
     双向绑定:
        主动勾选,则绑定的值为true,主动不勾选
        则为false
<input type="text" v-model="count" :style="myStyle">
<input type="checkbox" v-model="myFlag">
    
    
    
v-on:后面绑定事件,激发事件之后联动执行绑定的函数<tagName v-on:事件="函数"  />
 语法糖:使用 @ 取代 v-on 绑定事件<tagName @事件="函数" />   
<button @click="count++">点我试试</button>
​
​
v-bind:绑定元素中属性,使之变为初始化的值,<tagName v-bind:属性名="初始化的值" />
    语法糖:使用 :代替 v-bind,<tagName :属性名="初始化的值" />
<img :src="mySrc" :title="message":style="myCss">

Vue实例

即MVVM中的VM,通过Vue实例来显示单向和双向绑定

const vm = new Vue({
    /* el:element的简写,用来选择管理的模板
            这里表示Vue实例 vm 管理我们上面的div */
    el:'#app',
    /* data:初始化的数据 */
    data:{
        属性名:属性值
    },
    /* 设置函数(此处也可以称之为方法,因为如果函数放置在
            对象中,则可以称之为方法) */
    methods:{
        函数名(){
            
        },
    },
})

函数 计算属性 侦听器

<div id="app">
    //由于成绩是number类型,输入框中都是字符串类型,所以需要v-model.number转换为number类型
    前端成绩: <input type="text" v-model.number="frontEndScore"> <br>
    后端成绩: <input type="text" v-model.number="backEndScore"> <br>
      <hr> 
    //注意由于这里的函数没有绑定事件,所以这里相当于调用函数,所以添加了括号
    //函数只能实现单向绑定
    总成绩(函数-单向绑定): <input type="text" v-model="sumScore()"> <br>
        
        
    //此处使用计算属性 注意计算属性永远不会使用括号,它就是一个属性,不会传值
    //计算属性既可以单向绑定又可以双向绑定
     总成绩(计算属性-单向绑定): <input type="text" v-model="totalScore"> <br>
        
    //v-model.lazy="" 开启延迟双向绑定,当用户点击回车时才开启双向绑定功能,如果不开启会导致用户一边输入,一边进行绑定计算
    总成绩(计算属性-单双向绑定): <input type="text" v-model.number.lazy="totalScores"> <br>
        
        
    //侦听器 同样可以单双向绑定,有几个参数设置几个侦听器
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
    const vm = new Vue({
        el:'#app',
        data:{
          frontEndScore:100,
          backEndScore:80,
          totalWatch:0,
        },
        //设置函数
        methods:{
            sumScore(){
               return this.frontEndScore + this.backEndScore 
            },
        },
    
        //设置计算属性
        computed:{
            //单向绑定
            totalScore(){
                return this.frontEndScore + this.backEndScore
            },
                
            //单双向绑定完全版
            totalScores:{
                //单向绑定
                get(){
                    return this.frontEndScore + this.backEndScore
                },
                //双向绑定 val是形参,就是主动填入的总成绩
                set(val){
                    let avgScore = val/2
                    this.backEndScore = avgScore
                    this.frontEndScore = avgScore
                },
            },
        },
        
        
        //设置侦听器
        watch:{
            //设置要侦听的值
            frontEndScore:{
                //立即执行一次侦听器 刚打开页面显示的值
                immediate:true,
                //newVal:形参,被侦听的数据更改后的值
                //oldVal:形参,被侦听的数据更改后的值
                
                handler(newVal,oldVal){
                    //总成绩=新的前端成绩 + 后端成绩
                    this.totalWatch = newVal + this.backEndScore
                },
                //实现双向绑定的话要同时侦听这三个属性 代码同上
            },
        },
    })
    
    //在Vue实例外调用侦听器
    vm.$watch('backEndScore',{
        immediate:true,
        handler(newVal,oldVal){
            this.totalWatch = newVal + this.frontEndScore
        }
    })
</script>

条件渲染

.test{
    width:100px;
    height:100px;
    background-color: pink; 
}
<div id="app">
    //v-model 不能取反
    隐藏元素: <input type="checkbox" v-model="flag1"> //一个复选框 flag1为true勾选
        <br>
    //v-if:后面如果绑定真值,元素显示,底层渲染,否则元素隐藏,底层不渲染,可以取反
            //v-if切换消耗较大,适用于切换不频繁的场合
    <div class="test" v-if="!flag1">测试</div>
​
​
    隐藏元素: <input type="checkbox" v-model="flag2">
        <br>
    //v-show:后面如果绑定一个真值,元素显示,底层渲染,否则元素隐藏,底层依然渲染,可以取反
        //元素隐藏只不过是在元素上添加了一个display:none 行内式
        //适用于切换频繁的场合,仅仅初始载入消耗较大
    <div class="test" v-show="!flag2">测试</div>
​
​
    //Vue2.4新特性 v-else-if  v-else 以上两个必须搭配v-if使用
    <button @click="count++">点我试试!</button>
    //template标签,Vue提供得用来设置指令的标签最终浏览器并不会解析此标签,也不会作用于真实DOM中 以下三个指令必须紧邻
    <template v-if="count===1">React世界排名第一</template>
    <template v-else-if="count===2">Vue紧随其后</template>
    <template v-else>jQuery濒临淘汰</template>
</div><script src="../node_modules/vue/dist/vue.js"></script>
<script>
    const vm = new Vue({
            el:'#app',
            data:{
                flag1:false,
                flag2:false,
                count:0,
            },
        })      
</script>

样式渲染

所谓样式渲染就是指使用Vue来灵活的控制页面中的样式 主要有以下两个思路

1: v-bind绑定class

:class="初始化的值"

初始化的值对应类名

(频繁使用!) :class="{类名1:初始化的值,类名2:初始化的值}"

如果初始化的值为真,则类名存在,为假,则类名不存在

class后面是数组: :class="['类名1','类名2']"

2: v-bind绑定style

:style="初始化的值"

初始化的值对应样式

:style="{样式名:初始化的值,样式名:初始化的值,}" 样式名必须使用小驼峰格式

<p :class="test1">绑定class,class后面是一个字符串</p><p :class="{box2:flag2,box3:flag3}">绑定class,class后面是一个对象</p><p :class="['box4','box5']">绑定class,class后面是一个数组</p><p :style="{backgroundColor:val1,color:val2}">绑定style,style后面是一个对象</p><script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                test1:'box1',
                flag2:null,
                flag3:99,
                val1:'tomato',
                val2:'white',
            },
        })
    </script>

列表渲染

//v-for:用来进行迭代,这个指定书写在哪个元素上,则这个元素会进行迭代
//1: 迭代数组
    v-for = "(alias,index) in 循环体"
    alias:别名
    index:索引,不是必须,如果不写小括号可以省略
    in:可以替换为of
   :key:绑定id值,而不是使用默认的索引,否则可能会出现使用 unshift时输入bug
   
   <table border="1px">
       <tr>
                <th>序号</th>
                <th>姓名</th>
                <th>性别</th>
                <th>住址</th>
                <th>操作</th>
       </tr>
    <tr v-for="(person,index) in persons" :key="person.id">
                <td>{{ index+1 }}</td>
                <td>{{ person.name }}</td>
                <td>{{ person.gender === 0?'女':'男' }}</td>
                <td>{{ person.location }}</td>
                <td><span style="cursor: pointer;"
                @click="del(index)">删除</span></td>
            </tr>
    </table><script src="../node_modules/vue/dist/vue.js"></script>
<script>
    const persons=[]
    new Vue({
        el:'#app',
            data:{
                /* persons:persons, */
                persons,
                hero,
            },
            methods: {
                del(index){
                    if(confirm('您确定删除本条记录吗?')){
                        this.persons.splice(index,1)
                    }
                },
            },
    })
</script>

事件修饰符与事件原型

常见的事件修饰符

事件修饰符就是对事件的补充 @事件.事件修饰符="函数"

  • @事件.stop="函数" 屏蔽事件传播

     <div @click="todo">
          <button @click.stop="dothis">屏蔽事件冒泡(事件传播)</button>
    </div>  //只会执行dothis不会执行todo
    
  • @事件.prevent="函数" 屏蔽元素固有的一些动作 例如 链接提交 表单提交

    <form action="./1-初识mvvm.html" 
    @submit.prevent="sub">
       <input type="submit" value="提交">
    </form>
    ​
    <a href="./1-初识mvvm.html" @click.prevent="go">链接提交</a>
    
  • @事件.once="函数" 只执行一次

     <button @click.once="count++">{{ count }}</button>
    
  • @keyup.键位名="函数" 当某个键位激发时执行后面的函数 @keydown.tab 注意tab键必须使用键盘键位落下

    <input type="text" placeholder="请点击w" @keyup.w="w">
    <input type="text" placeholder="请点击space" @keyup.space="space">
    <input type="text" placeholder="请点击enter" @keyup.enter="enter" >
    
事件原型
//如果函数没有参数,则底层自动给我们传递一个事件原型,就表示这个激发的事件
<button @click="touch1">点我试试!</button>
//如果函数存在实参,则不再默认底层传递事件原型了,如果我们还想使用,则需要自己传递实参 $event
<button @click="touch2('hello',$event)">点我试试!</button>new Vue({
    el:'#app',
    data:{
        content:'<em style="color:red">初始化的数据</em>',
    },
    methods:{
        //event:形参 表示自动传递的事件原型
        touch1(event){
            //event.target表示这次事件激发的目标 这里就是button元素节点
            let nodeBtn = event.target
            nodeBtn.innerHTML = this.content
        },
        touch2(val,event){
            event.target.innerText = val
        }
    },
})

表单双向绑定

//v-model.trim 去掉双向绑定的字符串两侧空格
用户姓名: <input type="text" v-model.trim="myForm.vname"> <br>
            用户密码: <input type="password" v-model.trim="myForm.vpass"> <br>
​
            // 此处value属性为事先写好,只要与
            //v-model双向绑定的值对应,则默认选中,与真假值无关 
性别: <input type="radio" name="gender" value="00000" v-model="myForm.vgender">女
      <input type="radio" name="gender" value="11111" v-model="myForm.vgender">男 <br>
​
            // 注意此处依然对应value属性值,由于可以操作多个数据
            //所以这里是一个数组 
爱好:         <input type="checkbox" name="hobby" value="soccer" v-model="myForm.vhobby">足球
            <input type="checkbox" name="hobby" value="running" v-model="myForm.vhobby">跑步
            <input type="checkbox" name="hobby" value="shopping" v-model="myForm.vhobby">购物
            <input type="checkbox" name="hobby" value="travel" v-model="myForm.vhobby">旅行
            <input type="checkbox" name="hobby" value="game" v-model="myForm.vhobby">游戏 <br>
            
            //注意这里最终双向绑定的v-model是书写在select标签内 
出差所在地:
            <select name="location" 
            v-model="myForm.vlocation">
                <option :value="city.id" 
                v-for="city in citys" 
                :key="city.id">{{ city.name }}</option>
            </select>
            <br>
                    
            <!-- 富文本框 -->
            个人介绍:
            <textarea name="info" cols="15" rows="3"
            placeholder="请输入个人概况" 
            v-model.trim="myForm.vInfo"></textarea> <br>
            <input type="submit" value="提交">
        </form>
    </div>
​
new Vue({
            el: '#app',
            data: {
                /* 在封装数据时尽量将相同逻辑的数据封装在一个对象中
                Vue3强烈推荐这种书写风格,切忌大量数据封装在data表层 */
                myForm: {
                    vname: '',
                    vpass: '',
                    vgender: '',
                    /* 复选框对应数组 */
                    vhobby: [],
                    vlocation:'4',
                    vInfo:'',
                },
                citys: [
                    { id: 1, name: '济南' },
                    { id: 2, name: '青岛' },
                    { id: 3, name: '杭州' },
                    { id: 4, name: '上海' },
                    { id: 5, name: '南京' },
                    { id: 6, name: '昆山' },
                    { id: 7, name: '深圳' }
                ]
            },
            methods: {
                mySub(){
                    console.log('同步被屏蔽,异步要开始啦')
                    console.log(this.myForm)
                }
            },
      })

过滤器

<div id="app">
        <table border="1px">
            <tr>
                <th>id</th>
                <th>姓名</th>
                <th>支付方式</th>
            </tr>
            <tr v-for="user in users" :key="user.id">
                <td>{{ user.id }}</td>
                <td>{{ user.name }}</td>
                <!-- {{ 被过滤的值|过滤器名 }} -->
                <td>{{ user.payType|myFilter }}</td>
            </tr>
        </table>
        <!-- 注意不能与v-model连用 -->
        <input type="text" :value="content|myFilter2">
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        const users = [
            { id: 1, name: 'elena', payType: 1, },
            { id: 2, name: 'nancy', payType: 2, },
            { id: 3, name: 'aleric', payType: 4, },
            { id: 4, name: 'tommy', payType: 3, },
            { id: 5, name: 'damon', payType: 3, },
            { id: 6, name: 'stefan', payType: 1, }
        ]
​
        /* 数据字典(密码本) */
        const payOptions = [
            { id: 1, type: '支付宝', },
            { id: 2, type: '微信', },
            { id: 3, type: '银行卡', },
            { id: 4, type: '现金', }
        ]
​
        new Vue({
            el: '#app',
            data: {
                users,
                content:'中华台北剑道选手权因疫情取消!',
            },
            /* 设置过滤器 */
            filters: {
                /* 
                    过滤器名(被过滤的值){
                        过滤器存在以下两个注意事项
                        1:过滤器不能使用this
                        2:过滤器不能与v-model连用
                        在表单中用 :value 替代
                    } 
                */
                myFilter(val) {
                    /* 
                        const arr = [1,2,3,4]
                        let value = arr.find(a=>a>=3)
                        // 3
                    */
                    const payObj = payOptions.find( 
                    payOption => payOption.id === val)
​
                    return payObj?payObj.type:''
                },
                myFilter2(val){
                    if(!val){
                        return ''
                    }
                    return val.replace('中华台北','中国台湾省')
                    .replace('选手权','锦标赛')
                }
            },
        })
    </script>

自定义指令

  • 1.全局自定义,全局的自定义指令一定书写在我们自己new的Vue实例之前

    <div id="app1">
         <p v-etoak="content"></p>
    </div>
    ​
    Vue.directive('etoak',{
        //渲染样式 el:形参 表示书写指令的元素节点,这里el就是p元素节点
        bind(el){
            el.style.backgroundColor = 'coral'
        },
        //渲染动作 el:同上 binding:就是这个元素 binding.value:就是这个指令元素绑定的值
        inserted(el,binding){
            el.innerHTML = binding.value.toUpperCase()
        }
    })
    new Vue({
        el:'#app',
        data:{
            content:'thisisetoak',
        }
    })
    
  • 2.局部自定义指令

    <div id="app2">
            <p v-etoak="content"></p>
            // 此处使用局部自定义创建一个 自定义指令用来
            //实现自动获取焦点,取代兼容性几乎没有的 autofocus 
            <input type="text" v-focus >
    </div>new Vue({
        data:{
            content:'loveu3000',
        },
        directives:{
            //设置指令名
            focus:{
                //渲染样式
                bind(el){
                    
                },
                //渲染动作
                inserted(el,binding){
                    //强制激发获取焦点
                    el.focus()
                }
            }
        }
    }).$mount('#app2')
    

指令补遗

  • v-pre :提示Vue实例不编译此指令存在的元素

    <h1 v-pre>{{ title }}</h1> //会直接显示大胡子表达式 不会展示里面的值
    
  • v-cloak :用来解决闪现问题

    <style>
            /* 凡是存在此属性的元素 */
            [v-cloak]{
                /* 隐藏 */
                display: none;
            }
    </style>
    //闪现问题:当真实DOM还未覆盖虚拟DOM时,会存在极短的时间被用户发觉,页面中显示插值语法,这对用户体验非常不友好,通过v-cloak可以解决此问题 
    //当虚拟DOM生成时,插值语法与指令语法无法被解析,所以直接作用于元素中,此处添加css隐藏元素,当真实DOM覆盖之后,指令元素已经被成功解析,元素上不再存在 v-cloak 所以此时css隐藏失效元素显示出来了 
    <p v-cloak>{{ title }}</p>
    

数据代理

一个对象可以对另一个对象属性进行操作,称之为数据代理

const person = {
    name:'胡桃',
    age:16,
}
//使用数据代理给对象添加属性
Object.defineProperty(person,'location',{
    //添加属性值
    value:'璃月',
    //设置可枚举,默认false不可枚举 即获取所有属性名 console.log(Object.keys(person))无法展示           location
    enumerable:true,
    //设置可写,默认false不可写
    writable:true,// 可以通过person.location = '地名' 进行修改
    
    //设置可配置 默认false不可配置(删除)
    configurable:true,  //console.log(delete person.location)
})
​
​
​
//_data:源对象
//vm:代理对象const _data = {
    name:'胡桃',
    age:16,
}
​
const vm = {
    $demo1:'原生属性1',
}
//进行代理
Object.defineProperty(vm,'name',{
    //读取vm的name属性执行此函数
    get(){
        console.log('name属性被读取,getter要执行了')
        return _data.name
    },
    //修改vm的name属性执行此函数 newVal就是传入的新的name值
    
    set(newVal){
        console.log('name属性被修改,setter要执行了')
        _data.name = newVal
    }
})

Vue2实现对象和数组可响应式

<div id="app">
    <ul>
       <li v-if="person.name">姓名:{{ person.name }}</li>
       <li>年龄:{{ person.age }}</li>
       <li>住址:{{ person.location }}</li>
       <li v-if="person.gender">性别:{{ person.gender }}</li>
       <li v-for="hobby in person.hobbies">{{ hobby }}</li>
    </ul>
    <button @click="add">添加性别</button>
    <button @click="del">删除姓名</button>
    <button @click="add2">添加爱好</button>
</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script>
    const vm = new Vue({
        data:{
            person:{
                name:'胡桃',
                age:16,
                location:'璃月',
                hobbies:['抽烟','喝酒','烫头'],
            },
        },
        
        methods:{
            add(){
                //给对象person,添加gender属性,属性值为'女'
                //this.person.gender = '女'
                //上面的写法可以给对象添加属性,但是由于没有实现可响应式,没有添加getter和setter函数,页面模板不会出现变动
                //以下写法 实现可响应式
                this.$set(this.person,'gender','女')
                //Vue.$set(this.person,'gender','女')
            },
            
            del(){
                this.$delete(this.person,'name')
                //Vue.$delete(this.name,'name')
            },
            
            add2(){
                //以下写法 没有实现可响应式功能
                //this.hobbies[3] = '敲代码'
               /* 
                        在Vue2中 对于数组实现可响应式与对象不同
                        必须使用以下 七个 封装过可响应式功能的
                        函数才可以实现可响应式
                        push()
                        unshift()
                        shift()
                        pop()
                        splice()
                        sort()
                        reverse()
                        这七个函数实现了可响应式功能,其它函数没有实现
                        这七个与js中的那七个不是一套,这是尤雨溪封装过以后的
                        加强版
               */ 
                this.hobbies.push('敲代码')
                
            },
        },
    }).$mount('#app')
</script>