vue学习笔记

第3章 Vue 语法

3.1 插值绑定

3.1.1 文本插值

{{}}直接输出内容

3.1.2 HTML插值

v-html,会被直接渲染成视图节点,

3.2 属性绑定v-bind:/:

3.2.2 类名、样式绑定

三种方式:

  1. 字符串classStr: 'class1 class2 class3'
  2. 数组classArr: ['class1', 'class2', 'class3']
  3. 对象classObj: {'class1': true/false,....}

3.3 事件绑定v-on:/@

3.3.2 常见修饰符

可后缀于事件名称之后:@click.prevent=""

  • .stop -当事件触发时,阻止事件冒泡;
  • .prevent -当事件触发时,阻止默认行为
  • capture -当事件触发时,阻止事件捕获
  • .self -限制事件仅作用于节点自身
  • .once -事件被触发一次后即解除监听
  • .passive -移动端,限制事件用不调用preventDefault()方法

3.3.3 按键修饰符

.delete .tab .enter .esc .space .left .up .right .down
@click.enter=""

3.3.3 组合修饰符

.ctrl .alt .shift .meta
@click.ctrl="" @click=""

3.4 双向绑定v-model

3.4.2 v-model与修饰符

  • .lazy -将输入的数据赋值于变量的时机由输入时延迟到数据改变时
  • .number -自动转换输入为数值类型
  • .trim自动过滤输入的首尾空白字符
    v-model.trim.number=""

3.4.3 v-model与自定义组件

??????

3.5 条件渲染v-if/v-show与列表渲染v-for

3.5.1 v-if和v-show

v-if=""
v-show="" 只是简单的切换 元素的CSS属性:display,其不支持template元素

3.5.2 v-for

  • v-for="item in items"v-for="item of items"
  • 可以用index作为第二个参数标识下标(item, index) in/of items
  • 渲染一个对象的键值对:
    如:
<ul>
    <li v-for="(user, index) in users">
        ...
        <ul>
            <li v-for="(value, key) of user">
                ...
            </li>
        </ul>
    </li>
</ul>

与数据响应有关的吗数组方法:

  • push -将一个或多个元素添加至数组末尾,并返回新数组的长度
  • pop -从数组中删除并返回最后一个元素
  • shift -从数组中删除并返回第一个元素
  • unshift -将一个或多个元素添加至在数组开头,并返回新数组长度
  • splice -从数组中删除火元素或向数组添加元素
  • sort -对数组元素排序,默认按照Unicode编码排序,返回排序后的数组
  • reverse 将数组中的元素位置颠倒,返回颠倒后的数组

注意:
直接使用下标/键名为数组 /对象设置成员时:
arr[0] = 99
obj['key'] = 'value'
Vue并不会将其加入数据响应式系统,因此视图并不会改变

3.5.3列表渲染中的key

为每个迭代元素提供一个值不重复的key,不要使用index

<li v-for="item in items" :key="item.id"></li>

第4章 Vue选项

4.1 数据方法

4.1.1 数据选项data

数据(data)可接受的类型有对象(data: {})和函数(data () {})两种,不过在定义组件时只能使用函数类型
注意:不要将已声明的对象用于data选项,应该创建新的对象,或者使用JSON.parse(JSON.stringify(obj))深拷贝已有对象:

let Jack = {
    counter: 0
}
Vue.component('button-counter', {
    data() {
        return JSON.parse(JSON.stringify(jack))  //深拷贝
    },
    template: '<button @click="++counter && (console.log(\'click\'))">click {{counter}} times</button>'
})

选项属性props

为组件注册动态特性,可以是数组或者对象类型,用于接收从父组件传递过来的参数,并允许为其设置默认值(default)、类型检测(type)、校验规则(validator)等

方法选项methods

methods选项,不要用箭头函数在其中定义方法,否则this将无法正确指向Vue实例,因为使用箭头函数不会创建函数作用域。

计算属性computed

也不能用箭头函数,其依赖于响应式属性,所以当且仅当响应式属性变化时,计算属性才被重新计算,得到的结果被缓存,直到响应式属性再次被改变。

侦听属性watch

watch更重于处理数据变化时的业务逻辑,而computed更注重衍生数据,watch还可以异步修改数据

4.3 DOM渲染

4.2.1 指定被挂载元素el

1.CSS选择器

el: '#app'

2.DOM节点对象

el: document.getElementById('app2)

3.$mount方法

vm.$mount('#app')

4.2.2 视图的字符串模板template

4.2.3 渲染函数render

createElement来创建DOM节点,可接收三个参数:

  1. HTML标签字符串 | 组件选项对象 | 节点解析函数
  2. 定义节点特性的对象
  3. 子节点
render (createElement) {
    return createElement('div',{
        节点特性对象(style,class,attes,domProps,on等)  // domProps用于绑定DOM属性,innerHTML、innerText等
    },
    '子节点'
    )
}

4.2.4 选项的优先级

优先级:render>template>el

4.3 封装复用

4.3.1 过滤器filters

可在双括号插值(Mustache语法)中添加在JavaScript表达式的尾部,以|间隔,表达式的值将作为形参传入。

4.3.2 自定义指令

关注bind和update两个钩子函数

4.3.3 组件的注册components

4.3.4 混入的使用mixins

灵活的分发组建中一些可复用的功能。
混入冲突时的默认策略:

冲突选项合并策略冲突策略
data合并根节点数据优先采用组件的数据
mounted等钩子函数混合为数组全部调用且优先调用mixin的钩子函数
methods/components/directives混为同一对象优先采用组件的键值对
watch混合为数组全部调用且优先调用mixin的watch方法

第5章 Vue内置组件

5.1 组件服务

5.1.1 动态组件

component接收一个名为is的属性,is的值应为父组件中注册过的组件名称,用法如下:

<component :is=""view></component>   <!--view为变量-->

5.1.2 使用内置插槽分发内容slot

定义多个插槽时:使用name进行区分,如未指定name,则会将插槽内容至于默认插槽中。

5.1.3 组件的缓存keep-alive

keep-alive应出现在组件被移除后需要再次被挂载的地方,
如使用动态组件时:

<keep-alive>
    <component :is="view"></component>
</keep-alive>

或使用v-if时:

<keep-alive>
    <one v-if=""isOne></one>
    <two v-else></two>
</keep-alive>

它还可以接收includeexclude两个props属性:

  • include -只有匹配的组件会被缓存
  • exclude -被匹配的组件不会被缓存

5.2 过渡效果

5.2.1 单节点的的过渡transition

style:
v-enter,v-leave-to;v-enter-active,v-leave-active;
<transition>
    <div>...</div>
</transition>
自定义动画:transitionName-enter.....
style:
transitionName-enter.......
<transition name="transitionName">
    <div>...</div>
</transition>
引入动画库:enter-class,enter-active-class
<transition 
    name="custom"
    enter-active-class="animated 动画名字"
    leave-active-class="animated 动画名字">
    ......
</transition>
专门的初始渲染过度:appear
<transition 
    appear
    appear-class="custom-appear-class"
    appear-to-class="custom-appear-to-class"
    appear-active-class="custom-appear-active-class">
    ......
</transition>
复用时

Vue元素复用时,需要赋予元素唯一的key值重建新的元素,并且用in-outout-in防止两个元素同时出现:

<transition mode="out-in">
    <div :key="isMaster ? 'master : 'other'">...</div>
</transition>

5.2.2 多节点过渡transition-group

  1. 将以真实元素呈现,默认为span,可以通过tag属性更换为其他
  2. 过渡模式不可用
  3. 内部元素必须提供唯一的key
<transition-group name="list" tag="ul">
<li>...</li>
</transition-group>
用于改变元素定位的动画v-move

改变元素定位,定义方式与v-enter等一致,

第6章 Vue项目化

6.1 快速构建项目

6.1.2 使用Vue CLI构建项目

详见另一篇快速开始一个Vue项目

6.2 前端路由

6.2.1 前端路由的简单实现

Node.js创建服务端文件,服务端文件app.js代码如下:

const http = require('http');  // http模块
const fs = require('fs');  // 文件处理模块
const hostName = '127.0.0.1';
const port = 3000;
const server = http.createServer(function (req, res) {  // 创建http服务
    let content = fs.readFileSyns('index.html');  // 读取文件
    res.writeHead(200, {  // 设置响应内容类型
        'content-type': 'text/html;charset="utf-8'
    });
    res.write(content);  // 返回index.html文件内容
    res.end()
});
server.listen(port, hostName, function() {  // 启动服务监听
    console.log(`Server is running here: http://${hostName}: ${port}`)
})

安装Node后,在app.js文件所处目录下输入命令node app.js,当控制台出现Server is running here: http://127.0.0.1:3000时,即表示服务器启动成功。
使用Vue实现前端路由:

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<div id="app">
    <ul>
        <li><router-link to="/">Home</router-link></li>
        <li><router-link to="/about">About</router-link></li>
    </ul>
    <router-view></router-view>
</div>
<script>
    let Home = {
        template: '<h1>This is Home!</h1>'
    };
    let About = {
        template: '<h1>This is About!</h1>'
    };
    let routes = [  //定义路由规则
        {
            path: '/',
            component: Home
        },
        {
            path: '/about',
            component: About
        }
    ];
    let RouterLink = {
        props: ['to'],
        template: '<a :href="to"><slot name="default"></slot></a>'
    };
    let RouterView = {
        data () {
            return {
                url: window.location.pathname  // 获取浏览器地址
            }
        },
        computed: {
            ViewComponent () {  // 根据浏览器地址返回相应组件
                return routes.find(route => route.path === this.url).component
            }
        },
        render (h) {
            return h(this.ViewComponent)
        }
    };
    /* eslint-disable*/
    let vm = new Vue ({
        el: '#app',
        components: {
            RouterLink,
            RouterView
        }
    })
</script>

使用原生JS实现前端路由:

<div>
    <ul>
        <li><a href="#/">Home</a></li>
        <li><a href="#/about">About</a></li>
    </ul>
    <!-- 动态视图被挂载的元素 -->
    <div id="view"></div>
</div>
<script>
    let Home = '<h1>This is Home!</h1>';  // 视图模板Home
    let About = '<h1>This is About</h1>';  // 视图模板About
    let Router = function (el) {  // 定义路由类
        let view = document.getElementById(el);
        let routes = [];  // 路由规则列表
        let load = function (route) {  // 加载视图
            route && (view.innerHTML = route.template)
        };
        let redirect = function () {  // 分发视图
            let url = window.location.hash.slice(1) || '/';
            for (let route of routes) {
                url === route.url && load(route)
            }
        };
        this.push = function (route) {  // 添加路由规则
            routes.push(route)
        };
        window.addEventListener('load',redirect, false);  // 页面加载时
        window.addEventListener('hashchange', redirect, false)  // URL变化时
    };
    let router = new Router('view');  // 实例化路由
    router.push({
        url: '/',
        template: Home
    });
    router.push({  // 添加路由规则
        url: '/about',
        template: About
    })
</script>

6.2.2 Vue中的前端路由

Vue Router
RouterLink: 默认渲染成一个<a>标签,to属性用于指定跳转连接

<router-link to=""></router-link>

RouterView: 负责挂载路由匹配到的视图组件

<router-view></router-view>
1.基础路由
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
    <ul>
        <li>
            <router-link to="/">Home</router-link>
        </li>
        <li>
            <router-link to="/about">About</router-link>
        </li>
    </ul>
    <router-view></router-view>
</div>
<script>
    let Home = {
        template: '<h1>This is Home!</h1>'  // Home组件
    };
    let About = {
        template: '<h1>This is About!</h1>'  // About组件
    };
    let routes = [  // 定义路由规则,每一个路由规则应该映射一个视图组件
        {
            path: '/',
            component: Home
        },
        {
            path: '/about',
            component: About
        }
    ];
    let router = new VueRouter({  // 创建Vue Router实例,并传入routes配置
        routes
    });
    let app = new Vue ({
        router
    }).$mount('#app')
</script>
2. 动态路由
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
    <ul>
        <li><router-link to="/">Home</router-link></li>
        <li @click="add">
            <!--2. 参数num由实例传入路由-->
            <router-link :to="'/about/' + num">About</router-link>
        </li>
    </ul>
    <router-view></router-view>
</div>
<script>
    let Home = {
        template: '<h1>This is Home!</h1>'
    };
    let About = {
        template: `<div>
            <h1>This is About!</h1>
            <p>num: {{$route.params.num}}</p>  // 3. 在组件中显示参数num
        </div>`
    };
    let routes = [
        {
            path: '/',
            component: Home
        },
        {
            path:  '/about/:num',  // 1. 定义了参数num,格式如:/:num
            component: About
        }
    ];
    let router = new VueRouter ({
        routes
    });
    let app = new Vue ({
        data() {
            return {
                num: 0
            }
        },
        methods: {  // 当点击About时,num值自增1
            add() {
                this.num++
            }
        },
        router
    }).$mount('#app')
</script>
3. 嵌套路由
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
    <ul>
        <li><router-link to="/">Home</router-link></li>
        <li>
            <div><router-link to="/about">About</router-link></div>
            <ul>
                <!--3. 使用嵌套路由-->
                <li><router-link to="/about/author">About-Author</router-link></li>
                <li><router-link to="/about/email">About-Email</router-link></li>
            </ul>
        </li>
    </ul>
    <router-view></router-view>
</div>
<script>
    let Home = {
        template: '<h1>This is Home!</h1>'
    };
    let About = {
        template: `<div>
            <h1>This is About!</h1>
            <router-view></router-view>  // 1. 嵌套的动态视图区
        </div>`
    };
    let Author = {
        template: '<p>Author: lonely dawn</p>'
    };
    let Email = {
        template: '<p>Email: lonelydawn@sina.com</p>'
    };
    let  routes = [
        {
            path:  '/',
            component: Home
        },
        {
            path: '/about',
            component: About,
            children: [  // 2. 嵌套子路由
                {
                    path: 'author',
                    component: Author
                },
                {
                    path: 'email',
                    component: Email
                }
            ]
        }
    ];
    let router = new VueRouter ({
        routes
    });
    let app = new Vue ({
        router
    }).$mount('#app')
</script>
  • 嵌套路由可以实现在动态视图中嵌套动态视图;
  • 多层的动态视图也可以使用component来实现,不过刷新页面后会回到初始状态,而使用路由分发的视图刷新后会保持当前视图,并会在history留下记录。
4. 编程式路由
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
    <ul>
        <!--默认字符串为路径参数-->
        <li @click="redirectByPath('/')">Home</li>
        <li>
            <!--指定参数为路径-->
            <div @click="redirectByPath('/about')">About</div>
            <ul>
                <!--嵌套路由-->
                <li @click="redirectByPath('/about/author')">About-Author</li>
                <!--嵌套路由,动态路由,当使用path时params参数不生效-->
                <li @click="redirectByPath('/about/email',{email: 'lonelydawn@sina.com'})">About-Email</li>
                <!--嵌套路由,动态路由,可以直接将参数写入path-->
                <li @click="redirectByPath('/about/email/lonelydawn@sina.com')">About-Email</li>
                <!--嵌套路由,动态路由,使用命名路由跳转视图-->
                <li @click="redirectByName('Email', {email: 'sinledawn@sina.com'})">About-Email</li>
            </ul>
        </li>
    </ul>
    <router-view></router-view>
</div>
<script>
    let Home = {
        template: '<h1>This is Home!</h1>'
    };
    let About = {
        template: `<div>
            <h1>This is About!</h1>
            <router-view></router-view>  // 嵌套的动态视图区
        </div>`
    };
    let Author = {
        template: '<p>Author: lonely dawn</p>'
    };
    let Email = {
        template: '<p>Email: {{$route.params.email}}</p>'
    };
    let routes = [
        {
            path: '/',
            component: Home
        },
        {
            path: '/about',
            component: About,
            children: [
                {
                    name: 'Author',
                    path: 'author',
                    component: Author
                },
                {
                    name: 'Email',
                    path: 'email/:email',
                    component: Email
                }
            ]
        }
    ];
    let router = new VueRouter ({
        routes
    });
    let app = new Vue ({
        methods: {
            redirectByPath(path, params) {
                this.$router.push({path, params})
            },
            redirectByName (name, params) {
                this.$router.push({name, params: })
            }
        },
        router,
    }).$mount('#app')
</script>
  • 没有使用RouterLink组件,而是在JS中使用router.push方法跳转视图;
  • 还可以赋予路由name属性,通过name跳转视图;
  • 动态参数应放在params中,当使用path时,params不生效,此时应将参数值直接写进path。
5. Vue ClI快速构建项目中的router/index.js
  • 使用Vue.use(Router)安装Vue Router插件
  • export返回路由规则

6.3 状态管理

6.3.1 对象引用

6.3.2 状态管理器Vuex

State
vuex中的数据源,需要保存的数据就保存在这里,要确保应用只有唯一的数据源。
用法:

new Vuex.Store({  // 创建仓库
    state: {
        count: 1
    }
})

可以在页面通过$store.state.count来获取定义的数据,
Getters
相当于vue中的computed计算属性,Getter 中的派生状态在被计算之后会被缓存。
用法:

new Vuex.Store({
    state: {
        count: 1
    },
    getters: {
        tenTimesCount (state) {  // Vuex为其注入state对象
            return state.count * 10
        }
    }
})

getStateCount方法接收一个参数state,这个参数就是我们用来保存数据的那个对象;
在组件中,可以使用$store.getters.tenTimesCount
Mutations
提供修改State状态的方法。
用法:

new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        addCount (State, num) {
            state.count += num || 1
        }
    }
})

在组件中,直接使用$store.commit('funName') 提交mutation:

methods: {
    addCount() {
        this.$store.commit('addCount')
    }
}

Actions
类似Mutation,但:

  • Action 不能直接修改状态,只能通过提交mutation来修改
  • Action可以包含异步操作
    用法:
new Vuex.Store({
    state: {
    count: 0
    },
    mutations: {
        addCount (state, num) {
            state.count += num || 1
        }
    },
    actions: {
        // contex具有和store实例相同的属性和方法
        // 可以通过context获取state和getter中的值,或者提交mutation和分发其他的action
        addCountAsync (context, num) {
            setInterval(function(){
                if (context.state.count < 2000) {
                context.commit('addCount', num || 100)
                }
            }, num || 100)
        }
    }
})

在组件中,可以直接使用$store.dispatch('funName')分发action.
Moudules
定义模块

const counter = {
    namespaced: true,  // 定义为独立的命名空间
    state:{},
    ......
}

注册模块

new Vuex.Store({
    moudules: {
    counter
    }
})

mapStatemapGettersmapActions
在组件中,除了使用$stroe.state`这种写法,还可以用辅助函数映射

import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
export default {
    // 辅助函数的第一个参数为模块的名称
    computed: {
        ...mapState('counter', ['count']),   // ...是ES6中对象展开运算符
        ...mapGetters('counter', ['tenTimesCount'])
    },
    methods: {
    ...mapMutations('counter', ['addCount']),
    ...mapActions('counter', ['addCountAsync'])
    }
}

6.3.3 在项目中使用Vuex

在项目目录命令行输入cnpm install vuex --save-dev安装插件,
src目录下创建storestore/index.jsstore/modulesstore/modules/counter.js

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值