Vue.js 基础入门(一)——模板语法、常用特性

目录

一.Vue基础

二.Vue模板语法

1.指令

2.事件绑定

3.属性绑定

4.样式绑定

5.分支结构

6.循环结构

7.Tab选项卡综合

三.Vue常用特性 

1.表单操作

2.自定义指令

3.计算属性

4.侦听器

5.过滤器

6.生命周期

7.图书管理综合


一.Vue基础

  • Vue:构建用户界面的 渐进式 JavaScript框架
  • 渐进式:声明式渲染→组件系统→客户端路由→集中式状态管理→项目构建
  • Vue代码运行原理分析:Vue 代码 通过 Vue框架 转换为 原生JS
  • 官网:https://cn.vuejs.org/v2/guide/
  • 参数分析:
  1. el:元素的挂载位置(值:CSS选择器 / DOM元素)
  2. data:模型数据(值:对象)
  3. methods:声明方法
  4. directives: 自定义指令
  5. computed:计算属性
  6. watch:侦听器
  7. filters:过滤器
  8. components:组件

  • 插值表达式:将数据填充到 HTML标签,支持基本计算和字符串拼接
  • 前端渲染:将数据填充到 HTML标签中,产生静态HTML内容
  • 前端渲染方式:
  1. 原生js拼接字符串:代码风格差异大,后期维护困难
  2. 前端模板引擎:按规则写,后期维护方便,但缺少专门的事件机制
  3. vue特有的模板语法

二.Vue模板语法

  • 模板语法概览:插值表达式、指令、事件绑定、属性绑定、样式绑定、分支循环结构

1.指令

  • 指令:本质就是自定义属性,格式以 v- 开始

1.1 v-cloak指令

  • 使用 v-cloak 可解决:插值表达式存在的“闪动”问题
  • 解决原理:先通过样式隐藏内容,然后在内存中进行值的替换,替换好后再显示最终结果

1.2 数据绑定指令

  • 数据绑定:将数据填充到标签中
  • 数据绑定指令:
  1. v-text:填充纯文本,比插值表达式简洁,没有闪动问题,不会解析 html标签
  2. v-html:填充 HTML片段,存在安全问题,本网站内部数据可用,第三方数据不可用,会解析 html标签
  3. v-pre:填充原始信息,跳过编译过程,可加快静态内容渲染
  • v-text 为单向绑定:数据对象上的值改变,插值会发生变化;但插值发生变化,并不影响数据对象的值

1.3 响应式

  • HTML5中的响应式:屏幕尺寸变化,导致样式变化
  • 数据的响应式:数据变化,导致页面内容变化
  • v-once:只编译一次,显示内容后不再有响应式功能
  • data里定义了msg,后期我们修改了,仍然显示第一次 data里面存储的数据
  • v-once应用场景:如果显示的信息后续不需要再修改,可用v-once,提高性能

1.4 双向数据绑定指令

  • 双向数据绑定:
  • 当数据发生变化时,视图也发生变化
  • 当视图发生变化时,数据也发生变化
  • 当输入框中内容改变的时候,页面上的 msg 会自动更新
  • v-model:<input type='text' v-model='uname'/>
  • v-model 限制在这些地方使用: <input>、<select>、<textarea>、components

1.5 MVVM设计思想

  • MVC:后端分层开发; MVVM:前端分层开发
  • MVVM 分三部分:
  1. M(model):数据层,都放在 data里
  2. V((view):视图层,即HTML页面
  3. VM(View-Model):控制器,在数据层和视图层间建立联系,vm就是Vue实例

2.事件绑定

2.1 v-on指令处理事件

  • v-on指令用法:<input type=‘button' v-on:click='num++'/>
  • v-on简写:<input type=‘button' @click='num++'/>

2.2 事件函数调用

  • 直接绑定函数名:<button v-on:click='say'>Hello</button>
  • 调用函数:<button v-on:click='say()'>Hello</button>
  • methods里的函数,this 指向 vue实例,函数中若想使用 data里的数据,一定要加this

2.3 事件函数传参

  • 普通参数和事件对象:<button v-on:click='say("hi",123,$event)'>Say hi</button>
  • 事件绑定函数名,默认会传递 事件对象 作为事件函数的 第一个参数
  • 事件绑定函数调用事件对象 必须作为 最后一个参数 传递,并且事件对象的名称必须是 $event
  • 输入框中最新的值:event.target.value

2.4 事件修饰符

  • .stop 阻止冒泡: <a v-on:click.stop="handle">跳转</a>,event.stopPropagation();
  • .prevent 阻止默认行为:<a v-on:click.prevent="handle">跳转</a>,event.preventDefault();
  • 修饰符串联:v-on:click.stop.prevent=...
  • .self event.target 是当前元素自身时触发:<div v-on:click.self="doThat">...</div>

  • 使用修饰符时,顺序很重要,代码会顺序产生,因此:
  • v-on:click.prevent.self:阻止所有的点击
  • v-on:click.self.prevent:阻止对元素自身的点击

2.5 按键修饰符

  • .enter 回车键:<input v-on:keyup.enter='submit'>/<input v-on:keyup.13="submit">
  • 当点删除键 回车键时,调用方法:<input v-on:keyup.delete.enter='handle'>
  • 自定义按键修饰符:全局 config.keyCodes 对象  Vue.config.keyCodes.f1 = 113
  • 自定义按键修饰符命名自定义,但值必须是按键对应event.keyCode值

3.属性绑定

  • v-bind 指令用法:<a v-bind:href='url'>跳转</a>
  • 缩写:<a :href='url'>跳转</a>
  • v-model 底层实现原理分析:使用输入域中的最新的数据覆盖原来的数据
  • <input v-bind:value="msg" v-on:input="msg=$event.target.value">

4.样式绑定

4.1 class样式处理  

  • 对象语法:<div v-bind:class="{ active: isActive }"></div>  
  • 数组语法:<div v-bind:class="[activeClass, errorClass]"></div> 
  • 控制 isActive 在 true/false 间切换:this.isActive = !this.isActive;
  • this.activeClass = '';
  • 对象绑定和数组绑定可结合使用:
  • <div v-bind:class='[activeClass, {test: isTest}]'>测试样式</div>
  • 简写数组语法:arrClasses: ['active', 'error'],【data里声明】

4.2 style样式处理

  • 对象语法:<div v-bind:style="{ color: activeColor, fontSize: fontSize }"></div> 
  • 数组语法:<div v-bind:style="[baseStyles, overridingStyles]"></div>

4.3 绑定对象和绑定数组 的区别

  • 绑定对象时,对象属性=渲染类名,对象属性值=data中的数据
  • 绑定数组时,数组存的=data中的数据

5.分支结构

  • ⚫v-if  ⚫v-else  ⚫v-else-if  ⚫v-show
  • v-if VS v-show:
  1. v-if:控制元素是否渲染到页面
  2. v-show:控制元素是否显示(已经渲染到了页面)
  3. v-show本质:display设置为none,控制隐藏
  4. v-show只编译一次,v-if 不停的销毁创建,故 v-show 性能更好
  5. v-if 动态的向DOM树内添加删除元素
  6. v-if 切换有 局部编译/卸载 的过程

6.循环结构

  • v-for 遍历 数组:
  • <li v-for='item in list'>  {{item}}  </li>
  • <li v-for='(item,index) in list'>  {{item + '---' + index}}  </li>
  • <li :key='item.id' v-for='(item,index) in list'>  {{item}}  +  '---'  + {{index}}  </li>
  • :key的作用:区分不同元素,提高性能,高校更新虚拟DOM
  • v-for 遍历 对象:
  • <div v-for='(value, key, index) in object'></div> // 键值、键名、索引
  • v-if 和 v-for 结合使用(不推荐一起用,此时 v-for优先级更高):
  • <div v-if='value==12' v-for='(value, key, index) in object'></div> // 寻找键值为12的对象打印

7.Tab选项卡综合

  • 模板的结构和最终显示的效果基本一致
  • 把 data 中 title 利用 v-for 循环渲染到页面上
  • 把 data 中 path 利用 v-for 循环渲染到页面上
<div id="app">
        <div class="tab">
            <ul>
                <!-- 动态绑定class:有 active类名高亮  无 active类不高亮-->
                <li @click='change(index)' 
                    :class='currentIndex==index?"active":""' 
                    :key='item.id' 
                    v-for='(item,index) in list'> {{item.title}} </li>
            </ul>
            <!-- 动态绑定class:有 current类名显示  无 current类隐藏-->
            <div :class='currentIndex==index?"current":""' 
                 :key='item.id' 
                 v-for='(item, index) in list'>
                 <img :src="item.path">
            </div>
        </div>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {
                currentIndex: 0, // 选项卡当前的索引
                list: [{
                    id: 1,
                    title: 'apple',
                    path: 'img/apple.png'
                }, {
                    id: 2,
                    title: 'orange',
                    path: 'img/orange.png'
                }, {
                    id: 3,
                    title: 'lemon',
                    path: 'img/lemon.png'
                }]
            },
            methods: {
                change: function(index) {
                    this.currentIndex = index;
                }}});
    </script>

 

三.Vue常用特性 

  • 常用特性概览: ⚫ 表单操作  ⚫ 自定义指令  ⚫ 计算属性  ⚫ 侦听器  ⚫ 过滤器  ⚫ 生命周期

1.表单操作

  • 基于Vue的表单操作:
  1. Input 单行文本:v-model='uname',通过v-model 双向绑定 一个值
  2. textarea 多行文本:v-model='desc',data:{desc:''...
  3. select 下拉多选:v-model='occupation' multiple,data:{occupation: ['2', '3'],...
  4. radio 单选框:v-model='gender'相同,data:{gender: 2,.... ,每个单选框必要有value属性  且value 值不一样 
  5. checkbox 多选框:v-model='hobby'相同,data:{hobby: ['2', '3']...
  • 表单域修饰符:
  1. number:转化为数值 <input v-model.number="age" type="number">
  2. trim:去掉首尾空格
  3. lazy : 将 input事件 切换为 change事件,在“change”时而非“input”时更新

2.自定义指令

  • 局部指令(仅组件内可用):写在 vue实例内部
  • 全局指令(全局通用):写在 vue实例外部
  • 如果定义全局,Vue.directive 不是复数
  • 如果定义局部,directives: 是复数
  • 全局自定义指令:Vue.directive('focus' {  inserted: function(el) {  // 获取元素的焦点  el.focus();  }  })
  • 全局自定义指令用法:<input type="text" v-focus>
  • 带参数的自定义指令:Vue.directive(‘color', {  bind: function(el, binding) {  el.style.backgroundColor = binding.value.color;  }  })
  1. el 为当前自定义指令的 DOM元素 
  2. binding 为自定义的函数形参   通过自定义属性传递过来的值 存在 binding.value 里面
  • 带参数的自定义指令用法:<input type="text" v-color='{color:"orange"}'>
  • bind / inserted 使用效果几乎一样,带不带参数都可以用
  • bind声明周期, 只调用一次,指令第一次绑定到元素时调用。可以进行一次性的初始化设置
  • 局部自定义指令(写在vue实例里):directives: { focus: { inserted: function (el) { el.focus() } } }​​​​​​​
  • 局部指令只能在 当前组件 使用
  • 当全局指令和局部指令同名时,以局部指令为准

3.计算属性

  • 计算属性使模板内容更简洁
  • computed: {  reversedMessage: function () {  return this.msg.split('').reverse().join('')  }  } // 写在vue实例内
  • <div>{{reverseString}}</div>
  • 计算属性与方法的区别:计算属性是基于依赖进行缓存的,而方法不缓存​​​​​​​
  1. 计算属性进行缓存,控制台信息仅输出一次
  2. 方法不缓存,控制台信息输出两次

4.侦听器

  • 侦听器应用场景:数据变化时 执行异步 或 开销较大的操作
  • 数据一旦发生变化,就通知 侦听器绑定方法
  • watch 中的属性 一定是data中 已经存在的数据
  • watch: {  firstName: function(val){  // val表示变化之后的值  this.fullName = val + this.lastName;  },  lastName: function(val) {  this.fullName = this.firstName + val;  }  }
  • 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听

5.过滤器

  • 过滤器作用:格式化数据,比如将字符串格式化为首字母大写,将日期格式化为指定的格式等
  • 全局过滤器:Vue.filter('upper', function(val){  return val.charAt(0).toUpperCase() + val.slice(1);  })
  • 过滤器使用:
  1. <div>{{msg | upper}}</div>  :插值表达式过滤器
  2. <div>{{msg | upper | lower}}</div>:级联使用过滤器
  3. <div v-bind:id=“id | formatId"></div>:属性绑定过滤器
  • 局部过滤器:filters:{  过滤器名称: function(){}  }
  • 带参数的过滤器:Vue.filter(‘format’, function(value, arg1){  // value就是过滤器传递过来的参数  })
  • <div>{{date | format(‘yyyy-MM-dd')}}</div>

6.生命周期

  • vue实例 从创建到销毁 的过程中 ,会伴随着一些函数的自调用,这些函数叫 钩子函数
  • 挂载(初始化相关属性):
  1. beforeCreate:在实例初始化之后,数据观测和事件配置之前被调用,此时 data 和 methods 以及页面结构都没有初始化 什么都做不了
  2. created:在实例创建完成后被立即调用,此时 data 和 methods已经可以使用 但是页面还没有渲染出来
  3. beforeMount:在挂载开始之前被调用,此时页面上还看不到真实数据 只是一个模板页面
  4. mounted: el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子,数据已经真实渲染到页面上 在这个钩子函数里可用一些第三方插件
  • mounted:这个方法执行后,证明初始化完成,可以调用后端接口获取数据了
  • 更新(元素或组件的变更操作):
  1. beforeUpdate:数据更新时调用,发生在虚拟DOM打补丁之前,页面上数据还是旧的
  2. updated:由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子,页面上数据已更新
  • 销毁(销毁相关属性):
  1. beforeDestroy:实例销毁之前调用
  2. destroyed:实例销毁后调用

7.图书管理综合

7.1 数组相关API

  • 变异方法(修改原有数据):会影响数组的原始数据的变化
  • ⚫push(),后+1 ⚫ unshift(),前+1
  • ⚫ pop(),后-1⚫ shift(),前-1
  • ⚫ splice(),删除位置,删除个数,删除后替换值
  • ⚫ sort(),升序 ⚫ reverse(),倒序
  • 替换数组(生成新的数组):不会改变原数组,但返回一个新数组,需要赋值给原数组再显示
  • ⚫ filter():返回符合条件的新数组
  • concat(),链接多个数组,不改变现有的
  • ⚫ slice():截取开始位置,截取个数
  • 修改响应式数据:
  • Vue.set(vm.list, 2, 'lemon');
  • vm.$set(vm.list, 1, 'lemon');
  • vm.$set(vm.info, 'gender', 'female'); 也可以添加设置新属性
  1. vm.items:要处理的数组名称
  2. indexOfItem:要处理的数组的索引 
  3. newValue:处理后数组的值

7.2 常用特性应用场景

  1. 过滤器(格式化日期)
  2. 自定义指令(获取表单焦点)
  3. 计算属性(统计图书数量)
  4. 侦听器(验证图书存在性)
  5. 生命周期(图书数据处理)
<body>
    <div id="app">
        <div class="grid">
            <div>
                <h1>图书管理</h1>
                <div class="book">
                    <div>
                        <label for="id">
              编号:
            </label>
                        <!-- 禁用绑定属性::disabled="flag",修改时才会禁用 -->
                        <input type="text" id="id" v-model='id' :disabled="flag" v-focus>
                        <label for="name">
              名称:
            </label>
                        <input type="text" id="name" v-model='name'>
                        <!-- 禁用绑定属性::disabled="submitFlag",提交名字不存在时才能提交 -->
                        <button @click='handle' :disabled="submitFlag">提交</button>
                    </div>
                </div>
            </div>
            <div class="total">
                <span>图书总数:</span>
                <!-- 计算属性 统计图书总数 -->
                <span>{{total}}</span>
            </div>
            <table>
                <thead>
                    <tr>
                        <th>编号</th>
                        <th>名称</th>
                        <th>时间</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <!-- 添加 :key='item.id' 提高vue性能 ,遍历图书列表数组 -->
                    <tr :key='item.id' v-for='item in books'>
                        <td>{{item.id}}</td>
                        <td>{{item.name}}</td>
                        <!-- 通过过滤器,将时间格式化 -->
                        <td>{{item.date | format('yyyy-MM-dd hh:mm:ss')}}</td>
                        <td>
                            <!-- 点击连接后,阻止默认跳转行为,并调用相应方法,根据id进行操作 -->
                            <a href="" @click.prevent='toEdit(item.id)'>修改</a>
                            <span>|</span>
                            <a href="" @click.prevent='deleteBook(item.id)'>删除</a>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
        /*
                      图书管理-添加图书
                    */
        Vue.directive('focus', { // 自定义全局指令,实现焦点自动锁定
            inserted: function(el) {
                el.focus();
            }});
        Vue.filter('format', function(value, arg) { // 自定义过滤器,实现时间格式化
            function dateFormat(date, format) {
                if (typeof date === "string") {
                    var mts = date.match(/(\/Date\((\d+)\)\/)/);
                    if (mts && mts.length >= 3) {
                        date = parseInt(mts[2]);
                    }           }
                date = new Date(date);
                if (!date || date.toUTCString() == "Invalid Date") {
                    return "";
                }
                var map = {
                    "M": date.getMonth() + 1, //月份 
                    "d": date.getDate(), //日 
                    "h": date.getHours(), //小时 
                    "m": date.getMinutes(), //分 
                    "s": date.getSeconds(), //秒 
                    "q": Math.floor((date.getMonth() + 3) / 3), //季度 
                    "S": date.getMilliseconds() //毫秒    };
                format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
                    var v = map[t];
                    if (v !== undefined) {
                        if (all.length > 1) {
                            v = '0' + v;
                            v = v.substr(v.length - 2);      }
                        return v;
                    } else if (t === 'y') {
                        return (date.getFullYear() + '').substr(4 - all.length);    }
                    return all;  });
                return format; }
            return dateFormat(value, arg);   })

        var vm = new Vue({
            el: '#app',
            data: {
                flag: false, // 编号的禁用绑定属性
                submitFlag: false, // 提交按钮的禁用绑定属性
                id: '', // 用户输入的图书编号
                name: '', // 用户输入的图书名
                books: [] // 书籍列表
            },
            methods: {
                handle: function() { // 提交按钮绑定的方法
                    // 提交按钮点击有两种情况:添加图书 / 修改图书,根据禁用状态确定的
                    if (this.flag) { // 修改图书状态 flag是true,证明编辑编号区域被禁用 是修改才做
                        // 就是根据当前的ID去更新数组中对应的数据
                        this.books.some((item) => {
                            if (item.id == this.id) { // 如果图书列表的id = 点击的id
                                item.name = this.name; // 那么图书列表的书名 改成 现在输入框的书名
                                // 完成更新操作之后,需要终止循环
                                return true;
                            }
                        });
                        this.flag = false; // 修改完成后,解除编号输入框的禁用状态
                    } else {
                        // 添加图书 flag是false,证明编号禁用状态解除,即可以编辑编号,是添加操作
                        var book = {}; // 新建一个图书对象
                        book.id = this.id;
                        book.name = this.name;
                        book.date = new Date();
                        this.books.push(book); // 将图书对象追加到图书列表后面
                    }
                    // 执行完添加/修改操作后,清空表单输入框
                    this.id = '';
                    this.name = '';
                },
                toEdit: function(id) { // 接收用户点击的id
                    // 禁止修改ID
                    this.flag = true;
                    // 根据ID查询出要编辑的数据
                    var book = this.books.filter(function(item) {
                        return item.id == id;
                    });
                    // 把获取到的信息填充到表单
                    this.id = book[0].id;
                    this.name = book[0].name;
                },
                deleteBook: function(id) {
                    // 删除图书
                    // 根据id从数组中查找元素的索引
                    // var index = this.books.findIndex(function(item){
                    //   return item.id == id;
                    // });
                    // 根据索引删除数组元素
                    // this.books.splice(index, 1);
                    // -------------------------
                    // 方法二:通过filter方法进行删除
                    this.books = this.books.filter(function(item) {
                        return item.id != id; // 查询所有跟点击id不同的数组元素并展示
                    });
                }
            },
            computed: { // 计算属性
                total: function() {
                    return this.books.length; // 计算图书的总数
                }
            },
            watch: { // 监听器
                name: function(val) { // val是用户输入的值
                    // 验证图书名称是否已经存在
                    var flag = this.books.some(function(item) {
                        return item.name == val;
                    });
                    if (flag) { // 图书名称存在 
                        this.submitFlag = true; // 开启提交按钮禁用状态
                    } else { // 图书名称不存在     
                        this.submitFlag = false;
                    }   } },
            mounted: function() {
                // 该生命周期 钩子函数 被触发时,模板已可以使用
                // 此时用于获取后台数据,然后把数据填充到模板
                // 这里用写死的模板数据假装后台数据返回值
                var data = [{
                    id: 1,
                    name: '三国演义',
                    date: new Date() // 获取系统时间
                }, ...];
                this.books = data;
            }});
    </script>
</body>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lyrelion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值