vue相关

Vue
组件化
双数据绑定

是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
Object.defineProperty(obj , prop,{})
第一个参数目标对象,第二个参数属性,第三个参数是目标属性所拥有的特性以对象的方式

var obj  = {
     };
Object.defineProperty(obj, 'name', {
     
        get: function() {
     
            console.log('我被获取了')
            return val;
        },
        set: function (newVal) {
     
            console.log('我被设置了')
        }
})
obj.name = 'fei';//在给obj设置name属性的时候,触发了set这个方法
var val = obj.name;//在得到obj的name属性,会触发get方法

observer用来实现对每个vue中的data中定义的属性循环用Object.defineProperty()实现数据劫持,以便利用其中的setter和getter,然后通知订阅者,订阅者会触发它的update方法,对视图进行更新。

为什么要订阅者,在vue中v-model,v-name,{ {}}等都可以对数据进行显示,也就是说假如一个属性都通过这三个指令了,那么每当这个属性改变的时候,相应的这个三个指令的html视图也必须改变,于是vue中就是每当有这样的可能用到双向绑定的指令,就在一个Dep中增加一个订阅者,其订阅者只是更新自己的指令对应的数据,也就是v-model='name’和{ {name}}有两个对应的订阅者,各自管理自己的地方。每当属性的set方法触发,就循环更新Dep中的订阅者。

observer实现,主要是给每个vue的属性用Object.defineProperty(),代码如下:

function defineReactive (obj, key, val) {
     
    var dep = new Dep();
        Object.defineProperty(obj, key, {
     
             get: function() {
     
                    //添加订阅者watcher到主题对象Dep
                    if(Dep.target) {
     
                        // JS的浏览器单线程特性,保证这个全局变量在同一时间内,只会有同一个监听器使用
                        dep.addSub(Dep.target);
                    }
                    return val;
             },
             set: function (newVal) {
     
                    if(newVal === val) return;
                    val = newVal;
                    console.log(val);
                    // 作为发布者发出通知
                    dep.notify();//通知后dep会循环调用各自的update方法更新视图
             }
       })
}
        function observe(obj, vm) {
     
            Object.keys(obj).forEach(function(key) {
     
                defineReactive(vm, key, obj[key]);
            })
        }

实现compile:

compile的目的就是解析各种指令称真正的html。

function Compile(node, vm) {
     
    if(node) {
     
        this.$frag = this.nodeToFragment(node, vm);
        return this.$frag;
    }
}
Compile.prototype = {
     
    nodeToFragment: function(node, vm) {
     
        var self = this;
        var frag = document.createDocumentFragment();
        var child;
        while(child = node.firstChild) {
     
            console.log([child])
            self.compileElement(child, vm);
            frag.append(child); // 将所有子节点添加到fragment中
        }
        return frag;
    },
    compileElement: function(node, vm) {
     
        var reg = /\{
     \{
     (.*)\}\}/;
        //节点类型为元素(input元素这里)
        if(node.nodeType === 1) {
     
            var attr = node.attributes;
            // 解析属性
            for(var i = 0; i < attr.length; i++ ) {
     
                if(attr[i].nodeName == 'v-model') {
     //遍历属性节点找到v-model的属性
                    var name = attr[i].nodeValue; // 获取v-model绑定的属性名
                    node.addEventListener('input', function(e) {
     
                        // 给相应的data属性赋值,进而触发该属性的set方法
                        vm[name]= e.target.value;
                    });
                    new Watcher(vm, node, name, 'value');//创建新的watcher,会触发函数向对应属性的dep数组中添加订阅者,
                }
            };
        }
        //节点类型为text
        if(node.nodeType === 3) {
     
            if(reg.test(node.nodeValue)) {
     
                var name = RegExp.$1; // 获取匹配到的字符串
                name = name.trim();
                new Watcher(vm, node, name, 'nodeValue');
            }
        }
    }
}

watcher实现


function Watcher(vm, node, name, type) {
     
    Dep.target = this;
    this.name = name;
    this.node = node;
    this.vm = vm;
    this.type = type;
    this.update();
    Dep.target = null;
}

Watcher.prototype = {
     
    update: function() {
     
        this.get();
        this.node[this.type] = this.value; // 订阅者执行相应操作
    },
    // 获取data的属性值
    get: function() {
     
        console.log(1)
        this.value = this.vm[this.name]; //触发相应属性的get
    }
}

实现Dep来为每个属性添加订阅者

function Dep() {
     
    this.subs = [];
}
Dep.prototype = {
     
    addSub: function(sub) {
     
        this.subs.push(sub);
    },
    notify: function() {
     
        this.subs.forEach(function(sub) {
     
        sub.update();
        })
    }
}

梳理:
首先我们为每个vue属性用Object.defineProperty()实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep;然后在编译的时候在该属性的数组dep中添加订阅者,v-model会添加一个订阅者,{ {}}也会,v-bind也会,只要用到该属性的指令理论上都会,接着为input会添加监听事件,修改值就会为该属性赋值,触发该属性的set方法,在set方法内通知订阅者数组dep,订阅者数组循环调用各订阅者的update方法更新视图。

虚拟dom
获取监听变化后生成的虚拟节点树
与上一次虚拟DOM节点树进行比较
找到差异的部分,渲染到真实的DOM节点上面
更新试图
虚拟DOM技术使得我们的页面渲染的效率更高,减轻了节点的操作从而提高性能。虚拟节点树其实是一个普通JavaScript对象,新旧节点的对象比较,得出差异直接渲染页面。

vue的状态侦测只能到某一个组件上面,这是基于性能的考虑而得出的方案。组件内部通过diff算法来比对,从而渲染试图。

vue中通过模板来描述状态与试图之间的映射关系,把模板编译成渲染函数然后得到虚拟DOM节点树,最后使用虚拟节点树渲染页面。

1.vuex原理 包括(state,actions,mutations,getter,modules)各自的作用,怎么引用里边的数据,怎么传递的。
store文件里定义好module文件和index.js文件。index里需要引入使用到的组件vuex,vue都要引入,里边需要引入使用的module
vuex作用

2.vue的路由

import film from ‘@/views/film’....
import VueRouter from 'VueRouter'
vue.use(VueRouter)


const routes =[
	{
     path :'/film,'
	 component:film,
		children:{
     
			path :'/film,'
			component:film,
					},
        		{
     
        		path: '/film',
        		redirect: '/film/nowplaying'重定向
      			 }

	},

        组件先不加载,提高性能
	{
     path:"/center"
         component:()=>import(@/views/center)上边不用import引入

	}]
const router = new VueRouter({
     
mode:"hash",
routes


})
全局的路由拦截
router.beforeEach((to,from,next))=>{
     
    if(to.path==='/center'){
     
if(localStorage.getItem("token")){
     
     next()
}else{
     
     next("/login")
}
	}


}

局部配置
刚进入的时候
beforeRouteEnter(to ,from ,next){
     
if(localStorage.getItem("token"))

      }


更新
beforeRouteUpdate(to ,from ,next)
离开这个页面时
beforeRouteLeave

3.引入自己封装的组件步骤
先在componets里写好封装的组件
之后哪个页面引用就直接import xx from “路径”
components:{ xx组件名称 }

4.router-view:路由容器里边装结构,一般都是单组件文件,这页用完通常直接销毁

5.router-link 有:to=“里边装路径”tag="li"能让他编译成什么标签,activeClass="class名字"可以添加样式。点击哪个就让那个变样式

6.编程式导航:location.href。跳转页面
router-link跳转
this. r o u t e r . p u s h ( ) 例 子 : t h i s . router.push() 例子: this. router.push()this.router.back()返回上一级页面
this. r o u t e r . p u s h ( ‘ / d e t a i l / router.push(`/detail/ router.push(/detail/{id}`)跳转到括号里的页面路径
this. r o u t e r . g o ( 1 ) ; / / t h i s . router.go(1); // this. router.go(1);//this.router //路由对象
// this.$route 当前唯一匹配的路由对象
具体说明:
https://www.cnblogs.com/Leophen/p/11265833.html
7.获取路由参数
那么,如何在新页面中获取到传过来的参数 userId 呢?

在 mounted 钩子中使用 this.$route.params.xx. 获取传过来的参数,如下:

mounted () {
alert(this.$route.params.userId)
}
// 弹出123

this.$route.query.plan获取的是键值对,key:value

传入
简单写法
methods:{
toURL(){
this.KaTeX parse error: Expected 'EOF', got '}' at position 35: … '/demo2' }) }̲ } 传参的写法 method…router.push({ name: ‘demo2’, params: { userId: 123 }})
}
}

8.生命周期8个
new Vue()创建了一个vue对象
(1)beforecreate创建vue实例前的钩子函数
经过了:
1、observe data 开始监听data对象数据变化情况data(){return}
2、 init events 初始化vue内部事件methods:{}

(2)created 实例创建完成之后的钩子函数。

has el options yes—>开始编译模板 把data对象里面的数据和vue语法写的模板编译成html

(3)beforemount
开始挂载编译生成的html,到对应的位置时触发的钩子函数
此时还没将编译出的HTML渲染到页面上
create vm.$el and replace "el"将编译好的HTML替换el属性所指向的dom对象或替换对应HTML标签里面的内容

(4)mounted
将编译好的HTML挂载到页面完成后执行钩子函数, 此时可以进行发送ajax请求数据 获取数据的操作进行数据初始化
注意:mounted在整个实例生命内只执行一次

(5)beforeUpdate
当数据改变的时候,随时去更新dom。数据改变多少次就自动触发多少次。此时的data里的数据是新数据,但是没有同步到页面上
根据data的变化,在内存中重新渲染一个虚拟dom 树

(6)updated
渲染到页面上数据和页面都同步了

(7)beforedestroy
vue实例销毁之前执行的钩子函数。。销毁拆除所有观察者,子组件和事件监听

(8)destroyed
销毁完成

9.组件传值:父传子,子传父
父传子
(1)先在父亲组件里引入儿子组件
(2)父亲先在结构里写好儿子,之后再自定义一个属性例如:msg里边放着给儿子的值。
(3)儿子在自己的单独组件里定义一个props:[“msg”]接收父亲传过来的。
(4)之后儿子拿到父亲传过来的变量msg保存的值,渲染到页面上。例子:

{ {msg}}
或者v-for=“data in msg”。

子传父
(1)先在父亲组件里引入儿子组件
(2)儿子组件定义好事件@handliclick()和要传的值(例子:v-for="(data,index) in list" ),之后再methods里调用handliclick(){}
this. e m i t ( " e v e n t " , i n d e x ) 这 里 传 的 就 是 i n d e x 索 引 给 父 亲 。 ( 3 ) 父 亲 先 在 结 构 里 写 好 儿 子 组 件 名 称 < c h i l d @ e v e n t = " h a n d l e P r e v i e w ( emit("event",index)这里传的就是index索引给父亲。 (3)父亲先在结构里写好儿子组件名称emit("event",index)index3<child@event="handlePreview(event)>绑定好事件event。
(4)父亲在methods(){}里定义好事件handlePreview(index){}这就是通过形参index得到了儿子传过来的值。
10.常用的指令
v-if,v-else,v-else-if,v-bind 简写“:”绑定属性,v-on简写“@”绑定事件,v-if,v-show,v-for,v-model自定义属性

v-if是可以当分支语句使用也可以当渲染结构语句使用;
v-if和v-show区别:v-if:只有在值为true的时候才会创建结构,要不然是不会创建的,它的值的变化会带来重绘,因为改变里结构需要计算元素位置
v-show 相当于css结构里的display:bolck,none。他的值的变化会带来重排,只是样式在改变,结构一开始就被创建出来。高频率的适合v-show
11.过滤器

主演:{ {data.actors|actorFilter}}

Vue.filter(“actorFilter”,function(data){return data.map(item=>item.name).join("")})

局部过滤器
//1.注册局部过滤器 在组件对象中定义
filters:{
‘过滤器的名字’:function(value){
}
}
//2.使用过滤器 使用管道符 |
{ {price | ‘过滤器的名字’}}
全局过滤器
// 注册全局的过滤器
//第一个参数是过滤器的名字,第二个参数是执行的操作

Vue.filter(‘reverse’,function(value) {
return value.split(’’).reverse().join(’’);
});

//使用跟 局部过滤器一样

12.axios与fetch
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

从浏览器中创建xmlhttprequests
从node.js里创建http请求
支持promise的Api
拦截请求和响应
取消请求
自动转换成json数据
客户端支持防御 XSRF

请求配置
axios({
url:""
method:“post/get/put/request/delete/head/options”

// headers 是即将被发送的自定义请求头
headers: {‘X-Requested-With’: ‘XMLHttpRequest’},
// data 是作为请求主体被发送的数据
// 只适用于这些请求方法 ‘PUT’, ‘POST’, 和 ‘PATCH’
data: {
firstName: ‘Fred’
},
})

可以发送多个请求
function fun1(){
return axios.get(./user1)
}
function fun2(){
return axios.get(./user2)
}

axios.all([fun1(),fun2()])
.then(axios.spread(function(acct,perms){
//两个请求都执行完了

}))

可以捕获错误

axios({
url:"",
method:"",
}).then(res=>{

}).catch(res=>{})

axios既提供了并发的封装,也没有fetch的各种问题,而且体积也较小。
防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
ajax的写法
$.ajax({
type: ‘POST’,
url: url,
data: data,
dataType: dataType,
success: function () {},
error: function () {}
});
打包文件 : npm run build
可以用webpack打包,自己配置。

你可能感兴趣的:(笔记,vue,前端)