美文网首页
vue learning

vue learning

作者: 你的宇哥哥 | 来源:发表于2018-08-24 15:21 被阅读11次

    安装Vue-cli

    // 全局安装vue-cli
    npm install -g @vue/cli
    
    // 安装vue-cli 2.x模板(旧版本)
    vue init webpack my-project
    
    // 安装vue-cli 3 模板
    vue create my-project
    // 也可以使用GUI界面来创建项目,vue ui
    
    查询vue版本
    vue --version
    

    Vue实例 - 生命周期

    new Vue()时的template

    template 就是选择Vue实例要即将加载哪个模板,
    App.vue是主程序

    // 写法1:
    import App from './App'    
    // 这里不用写App.vue,他会先搜索App.js然后再搜索App.vue一直搜索下去
    new Vue({
        el: '#root',
        template: '<App></App>',
        components: {
            App
        }
    })
    
    // 写法2:
    import App from './App'
    new Vue({
        el: '#root',
        render: h => h(App)
    })
    

    1、有template时,这个template里的内容会替换掉“el所指的那个”Dom节点(整个),就相当于outerHTML
    2、没有template时,会沿用原来的Dom节点,只是多了个Vue实例在上面

    模板语法

    v-once

    用v-once指令一次性插值。
    当数据改变时,插值出的内容也不会更新

    若绑定的值是null、undefined或false,则不会包含在渲染出来的元素中

    比如:
    <button v-bind:disabled="isButtonDisabled">Button</button>
    //如果IsButtonDisabled的值是null、undefined或false,则disabled特性不会被包含在渲染出来的button元素中
    

    计算属性和侦听器

    <div id="example">
        <p>{{ message }}</p>
        <p>{{ reversedMessage }}</p>
    </div>
    
    var vm = new Vue({
        el: '#example',
        data: {
            message: 'Hello'
        },
        computed: {
            // 声明了一个计算属性reversedMessage
            reversedMessage: function () {
                return this.message.split('').reverse().join('')
                // 这里return提及到的属性!!都是这个计算属性所要依赖的!
                // 当这些被依赖到的属性发生变化时,这个计算属性就会重新计算
            }
        }
    })
    
    // 所以可以像绑定普通属性一样在模板中绑定计算属性
    // 以声明的方式创建了这种依赖关系
    // -------
    // 和 直接使用函数 的区别:
    // 因为同样可以在 {{ reversedMsgFunction() }},然后methods里面写这个方法来return
    // 但是,计算属性是基于它们的依赖进行缓存的。
    // 即只要message还没有发生改变,多次访问reversedMessage计算属性就会立即返回之前的计算结果,而不必再次执行函数
    // --------
    // 如果是计算属性return Date.now()这样子的话,因为Date.now()没有在data对象里,所以只会在渲染初期的时候出现一次,以后不改
    // 如果是方法来return Date.now(),那就在每次调用方法的时候返回最新的当前时间
    

    计算属性的setter

    // ...
    computed: {
        fullName: {
            get: function () {
                return this.firstName + ' ' + this.lastName
            },
            set: function (newValue) {
                var names = newValue.split(' ')
                this.firstName = names[0]
                this.lastName = names[names.length - 1]
            }
        }
    }
    // 他的set方法将会在修改这个计算属性时被调用:
    // vm.fullName = 'John Doe'
    // 切记!在set方法里面,不能直接修改自己(即fullName),只能修改它所依赖的属性,比如(firstName、lastName),然后由它们,去改变fullName
    

    什么时候用侦听器watch?

    当需要在数据变化时,执行异步操作,或者开销较大的操作时
    // 比如:在用户输入完,才会执行某个函数(_.debounce,一个通过Lodash限制操作频率的函数)

    Class与Style绑定

    绑定Class列表

    // 对象语法(键值对的方式,来决定要不要渲染)
    <div :class="classObj"></div>
    
    data () {
        return {
            classObj: { 
                active: true
            }
        }
    }
    
    
    // 数组语法(变量取代的方式,来决定渲染该变量代表的是哪种)
    <div :class="classList"></div>
    
    data () {
        return {
            classList: [
                'active',
                'text-danger'
            ]
        }
    }
    
    // 在数组语法中,也可以嵌套进对象的语法
    <div :class="[ { active: isActive }, errorClass  ]"></div>
    
    // 好处是可以在methods里用this.classObj这样直接修改css
    

    用在自定义组件上的class

    在一个自定义组件上,用到class属性!
    那么这个class列表将会被添加到该组件的根元素(即template参数的第一层dom节点)上。(若有同名,不会被覆盖)

    绑定内联样式

    好处::style会自动侦测并添加相应的浏览器引擎前缀

    // 对象语法
    <div :style="styleObj"></div>
    
    data: {
        styleObj: {
            'color': 'red',
            'font-size': '20px'
        }
    }
    
    // 数组语法(配合 对象语法 使用)
    <div :style="[ baseStyles, styleObject ]"></div>
    data: {
        styleObject: {
            color: 'red',
            fontSize: '13px'
        },
        baseStyles: {
            fontFamily: '黑体'
        }
    }
    

    条件渲染

    key的作用

    【用key管理可复用的元素】
    key是Vue识别节点的一个通用机制。

    • Vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。
      你可以用key,来告诉Vue,“这两个元素是完全独立的!不要复用它们!”
      一般在v-for时,就提供key。
      ** 【一般用什么来作为key】 **
      尽可能使用渲染元素的自身的属性id,给渲染的元素绑定一个key值,
      这样在当前渲染元素的DOM结构发生变化时,能够单独响应该元素而不触发所有元素的重新渲染

    v-if 和 v-show

    v-if:
    1、直到条件第一次真时,才开始渲染
    2、可以确保在切换过程中,条件块内的 事件监听器子组件 能够适当地被摧毁和重建
    3、v-forv-if具有更高的优先级(也就是v-if里面,可以用v-for里迭代的内容)

    <li v-for="todo in todos" v-if="!todo.isComplete">
        {{ todo }}
    </li>
    

    列表渲染

    v-for

    v-for中,拥有对 父作用域属性 的完全访问权限

    一个数组的 v-for

    1、v-for="(item, index) in items",第一个参数是当前项,第二个参数是当前项的索引
    2、可以用 of 替代 in,一样的~

    一个对象的 v-for

    1、v-for="(value, key, index) in items",第一个参数是属性值,第二个参数是键值,第三个参数为索引
    2、遍历对象时,是按Object.keys()来遍历的,所以不能保证他的结果顺序

    数组的变异、非变异方法

    变异方法。数组的方法中,能够触发视图更新的方法:

    • push( )
    • pop( )
    • shift( )
    • unshift( )
    • splice( )
    • sort( )
    • reverse( )

    非变异方法。数组的这些方法不会改变原始数组,但会返回一个新数组。
    可以用新数组去替换就数组就好了!

    • 用一个含有相同元素的数组,去替换原来的数组是非常高效的操作

    数组的更新检测

    Vue不能检测到以下变动的数组:
    1、利用索引去直接设置一个项,例如:vm.items[indexOfItem] = newValue
    2、直接修改length,例如vm.items.length = newLength

    • 这些都不能被Vue检测到,也就是说不能 立马 反应在视图上!(而是等到下次用set才会一齐更新)

    1的解决办法:
    用全局方法 —— Vue.set( )
    Vue.set(vm.items, indexOfItem, newValue)

    • 也可以用vm.$set( ),一样的,只是一个别名。
    • 这个vm是Vue实例的变量名

    2的解决办法:
    用splice( )
    vm.items.splice(newLength)

    对象的更新检测

    Vue也不能检测对象属性的添加或删除

    • 对于已经创建的实例,Vue不能 动态 添加根级别的响应式属性。
    • 但是可以用Vue.set(object, key, value)方法向嵌套对象添加响应式属性。

    解决办法:
    Vue.set(vm.userProfile, 'age', 27)

    • 也可以用vm.$set( ),一样的,只是一个别名

    一次添加多个属性时:
    vm.userProfile = Object.assign({ }, vm.userProfile, {
    age: 27,
    favoriteColor: 'green'
    })

    事件处理

    事件处理方法

    1、v-on 可以直接绑定一个方法(不是调用哦!)

    <button @click="greet"> Greet </button>
    
    methods: {
        greet: function (event) {
            console.log(event)
            // 这个event是原生DOM事件,即使不用传,也是有的
        }
    }
    

    2、v-on 也可以直接调用一个方法

    <button @click="greet('hi')"> Say hi </button>
    
    methods: {
        say: function (message) {
            alert(message)
        }
    }
    
    特殊变量$event(和原生event对象是一样的)

    有时候要访问原始DOM事件,就把特殊变量$event传到方法里(位置不重要)

    <button @click="greet('hi', $event)"> Submit </button>
    
    methods: {
        greet (message, ev) {
            console.log(ev)
            // 最好方法里只有纯粹的数据逻辑,而不是去处理DOM事件细节
        }
    }
    
    事件修饰符(如@click)
    • .stop
    • .prevent
    • .once
    // .stop:
    相当于ev.stopPropagation()
    在W3C组织的统一下,JS支持冒泡流、捕获流。
    JS事件流原理:
    捕获阶段 - 目标阶段 - 冒泡阶段
    所以,当点击一个按钮时,它的祖元素也可以被触发到“点击事件”。
    
    若在某个子元素上,用@click.stop这个事件修饰符可以防止向父元素冒泡,这样使得父元素触发不了“点击事件”啦!
    
    // .prevent:
    相当于ev.preventDefault()
    比如,可以阻止默认行为,比如跳转、提交等默认行为
    
    // .once:
    比如@click.once="doThis",则表明这个按钮的“点击事件”只能触发一次
    
    按键修饰符(如@keyup)

    这是为 监听键盘事件 用的

    • .enter
    • .tab
    • .esc
      等等

    可以通过全局 config.keyCodes 对象自定义 按键修饰符 的别名:
    Vue.config.keyCodes.f1 = 112
    // 112是键码
    // 可以使用 @keyup.f1

    系统修饰键(如@click、@keyup表示同时按下下面的)
    • .ctrl
    • .alt
    • shift
    • meta
    // 按住Alt + C
     <input @keyup.alt.67 = "greet" />
    
    鼠标按钮修饰符
    • .left(鼠标左键)
    • .right
    • .middle

    表单输入绑定

    复选框

    多个复选框,绑定到同一个数组

    //会把复选框的value自动push进arrays里!
    <div>
        <input type="checkbox" value="Jack" v-model="arrays">   
        <input type="checkbox" value="John" v-model="arrays">
        <span>{{ arrays }}</span>
    </div>
    
    data () {
        return {
            arrays: []
        }
    }
    
    下拉选择

    下拉选择列表(按CTRL可多选)

    //会把option的text文本节点自动push进arrays里!
    <select v-model="arrays" multiple>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>
    
    data () {
        return {
            arrays: []
        }
    }
    
    复选框value自定义
    <input
        type="checkbox"
        v-model="toggle"
        true-value="yes"
        false-value="no"
    >
    // true-value、false-value这两个值我们可以自定义,该复选框选中与否时的value
    // 选中
    vm.toggle === 'yes'
    // 没选中
    vm.toggle === 'no'
    
    修饰符
    • .lazy
    • .number
    // .lazy:
    可以将双向数据同步的时间节点,从 input 触发改为 change 触发
    <input v-model.lazy="msg" />
    {{ msg }}
    可以发现,在input框中输入时,下面的msg并没有改变(虽然触发了input事件)
    但是当离开焦点后,value改了,触发change了,下面msg才发生改变
    
    // .number:
    自动将用户的输入转为数值类型(默认是字符串)
    <input v-model.number="age" />
    
    // .trim:
    自动过滤用户输入的 首、尾 的空白字符
    <input v-model.trim="msg" />
    

    组件基础

    基础

    组件是可复用的Vue实例。
    我们可以在一个通过new Vue创建的Vue根实例中,把这个组件作为自定义元素来使用:

    <div id="root">
        <button-counter></button-counter>
    </div> 
    
    new Vue({ el: '#root' })
    
    • 创建组件时,也和new Vue一样接受相同的选项,例如:
      data、computed、watch、methods以及生命周期钩子
    • el这个选项是根实例才有的

    组件的复用

    每用一次组件,就会有一个它的新实例被创建,前提是:

    data 必须是一个函数

    data: function () {
        return {
            counter: 0
        }
    }
    // 这样每个实例可以维护一份 被返回对象的独立的拷贝
    // 不然会影响到其它所有实例
    

    组件的注册

    全局注册

    Vue.component('my-component-name', {
    // ...options...
    })
    特点:这个组件一直会被包含在最终的构建结果中,会造成用户下载的JS的无谓的增加。
    不用components注册了,直接可以用这个组件
    注意:全局注册的组件必须要在 Vue根实例创建之前就被注册,否则如下:
    [图片上传失败...(image-f03bd9-1535096135496)]

    局部注册
    var myHeader = {
        template: '<p>hello</p>'
        /// ...options...
    }
    
    new Vue({
        el: '#root',
        components: {
            'my-header': myHeader // 这里就是局部注册,只有这个父组件可以用
        }
    })
    
    基础组件的自动化全局注册

    如果有一些组件会在各个组件中被频繁用到,那就称为 基础组件

    import Vue from 'vue'
    import upperFirst from 'lodash/upperFirst'
    import camelCase from 'lodash/camelCase'
    
    const requireComponent = require.context(
      // 其组件目录的相对路径
      './components',
      // 是否查询其子目录
      false,
      // 匹配基础组件文件名的正则表达式(这里的正则表达式匹配的注意下,目前是任何文件都可以)
      /[A-Z]\w+\.(vue|js)$/
    )
    
    requireComponent.keys().forEach(fileName => {
      // 获取组件配置,即实例选项
      const componentConfig = requireComponent(fileName)
    
      // 获取组件的 PascalCase(大驼峰) 命名
      const componentName = upperFirst(
        camelCase(
          // 剥去文件名开头的 `'./` 和结尾的扩展名
          fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
        )
      )
    
      // 全局注册组件
      Vue.component(
        componentName,
        // 如果这个组件选项是通过 `export default` 导出的,
        // 那么就会优先使用 `.default`,
        // 否则回退到使用模块的根。
        componentConfig.default || componentConfig
      )
    })
    
    

    Prop

    当一个值传递给一个prop特性的时候,它就变成了那个组件实例的一个属性(就像访问data中的值一样)

    单个根元素

    每个组件里的模板,都必须包裹在一个且同一个父元素下

    在组件上使用v-model

    input中的v-model指令的实现原理:

    <input v-model="msg">
    // 等价于
    <input
     :value="msg"
     @input="msg = $event.target.value">
    

    由上面所知,如果要在自定义组件(输入框)上面实现v-model,那就要这样:

    // 组件注册时:
    Vue.component('custom-input', {
        props: ['value'],
        template: `
            <input
                :value="value"
                @input="$emit('input', $event.target.value)">
        `
        // 在组件中,其实是利用了名为 `value` 的 prop、通过emit触发 名为`input` 的事件并传入一个值
            // 注意了!!emit的第一个参数(事件名字)不能使用驼峰,因为不区分大小写!要改用短横线
    })
    
    // 组件使用时:
    <custom-input v-model="searchText"></custom-input>
    
    复选框如何用v-model?

    因为 v-model 默认会利用了名为 value 的 prop、名为 input 的事件,所以像 单选框复选框 这些输入控件的 value 好像不起作用(或者你打算用 value 来做其他事情)
    解决方法: 使用 model 选项

    Vue.component('base-checkbox', {
        model: {
            prop: 'checked',
            event: 'change'
        }, // 利用 model 选项,让 v-model 利用名为“value”的prop,名为“change”的事件
        props: {
            checked: Boolean
        },
        template:`
            <input
                type="checkbox"
                :checked="checked"
                @change="$emit('change', $event.target.checked)">
        `
    })
    
    // 组件使用时:
    <base-checkbox v-model="searchText"></base-checkbox>
    

    组件的is特性

    有些标签,如select、ul等等里面规定跟着option、li的,直接在其子元素插入组件会无效。也有可能会被作为无效的内容提升到 外部 (即和select这些同级),并导致最终渲染结果出错
    解决方法:

    <ul>
        <li is="comp"></li>
    </ul>
    
    // 最终的渲染效果:
    <ul>
        <div>...这里是comp的代码...</div>
    </ul>
    
    // 也就是“过桥拆板”的效果,li标签会被移花接木成了 组件 的模板代码
    

    相关文章

      网友评论

          本文标题:vue learning

          本文链接:https://www.haomeiwen.com/subject/axabiftx.html