vue和webpack的一点点了解

本文主要探讨Vue的双向绑定原理,生命周期,组件通信,路由管理以及Webpack的基础知识。通过Object.defineProperty()实现数据劫持和发布-订阅模式,完成数据同步与视图更新。同时讲解了Vuex在状态管理中的角色,以及Vue的模板与指令系统,最后涉及了Webpack在构建Vue项目中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

官网教程:https://cn.vuejs.org/v2/guide/installation.html

[参考资料]http://mp.weixin.qq.com/s/6Mo5csEDVKMq4-v6Yi8ZPQ)

参考资料

知识点总结

vue的主要作用是当数据发生改变时使用虚拟DOM来更改某一DOM节点,避免将整个页面渲染。

1.关于vue,像他是一种组件化的轻量级框架,它是基于什么前端设计模式的。
vue基于组件化的开发方式,用于构建用户界面的渐进式的js框架,自底层向上逐层应用,

Vue的双向绑定(你可以说这是vue最大的好处)

双向数据绑定是在单向的基础上给可输入元素(input、textare)添加change(input)事件,来动态修改model和view

实现数据绑定的方法:

发布者-订阅者模式(backbone.js)

脏值检查(angular.js) 

数据劫持(vue.js)

MVVM
M - model,指的是模型,也就是数据,V - view,指的是视图,也就是页面展现的部分。通常,我们需要编写代码,将从服务器获取的数据进行“渲染”,展现到视图上。每当数据有变更时,我们会再次进行渲染,从而更新视图,使得视图与数据保持一致。
另一方面,页面也会通过用户的交互,产生状态、数据的变化,这个时候,我们则编写代码,将视图对数据的更新同步到数据,以致于同步到后台服务器。也就是不同的前端 MV* 框架对于这种 Model 和 View 间的数据同步有不同的处理。

VueJS 则使用 ES5 提供的 Object.defineProperty() 方法,监控对数据的操作,从而可以自动触发数据同步。并且,由于是在不同的数据上触发同步,可以精确的将变更发送给绑定的视图,而不是对所有的数据都执行一次检测。

步骤:

第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

采用数据劫持和发布者-订阅者结合的方式,来做数据绑定,核心是object.defineProperty(),劫持各个属性的getter和setter,在数据模型变化的时候,发布消息给订阅者(绑定了数据模型的DOM元素),触发相应的监听回调。

双向链接

Object.defineProperty(obj, key, options)

直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。

vueJS采用 ES5 提供的 Object.defineProperty() 方法,监控对数据的操作,从而可以自动触发数据同步。并且,由于是在不同的数据上触发同步,可以精确的将变更发送给绑定的视图,而不是对所有的数据都执行一次检测。

有三个参数,全部都是必填的。参数:

obj:目标对象

key:属性或者方法的名字

options:目标属性所拥有的特性

主要解释第三个参数 {

value:属性的值,            

writable:布尔值,规定属性是否可重写, 在值为true的情况下,才能对该值进行重写修改。         

configurable:总开关,以第一次设置为准,一旦是false,则其他属性不可设置,            

enumerbale:决定属性是否可枚举 ,就是能不能被遍历出来。           

get: 是一个函数,返回一个值,会在属性被调用的时候触发。            

set: 是一个函数,接收一个新值,会在值被重写或修改的时候触发这个函数     

}
因为如果没有明确的设置其他值,默认都是false。

访问器:(set\get)不能和writable/value同时设置 就是会冲突的意思,set和writable都是设置属性值的,所以会冲突 而get和value都是获取属性值的,所以也会冲突(可以先这么理解)

//判断是不是对象

function isObj(obj){
    var type = Object.prototype.toString.call(obj);
    return type ==='[object Object]'
}

//执行函数

function ObjFun(obj){
   if(isObj(obj)){
       new Objserver(obj);
 }
}
function Observer(obj){
    this.data = obj;
    this.walk(obj);
}

 //监听事件函数:
Observer.prototype.walk = function(obj){
    for(var k in obj){
        def(obj,k,obj[k])
    }
}
function def(obj,k,val){
    Object.defineProperty(obj,k,{
        configurable:true,
        enumerable:true,
        get:function(){
            console.log('get取值');
            return val;
        },
        set:function(newVal){
            if(val === newVal){
                return;
            }
            val = newVal;
            console.log('set设置值')
        }
    });
}

//测试:
var obj = {a:111,b:222};
objFun(obj);
console.log(obj.a)//get取值 222
obj.a = 333;//set设置值
console.log(obj) 

装饰者模式
详细解释
在不改变对象自身的基础上,在程序运行期间给对象动态的添加职责

装饰器模式是一种结构型模式,它与对象的创建无关,主要考虑的是如何拓展对象的功能。也就是说,除了使用线性式(父-子-孙)继承方式之外,我们也可以为一个基础对象创建若干个装饰对象以拓展其功能。然后,由我们的程序自行选择不同的装饰器,并按不同的顺序使用它们。在不同的程序中我们可能会面临不同的需求,并从同样的装饰器集合中选择不同的子集。

观察者模式(发布-订阅模式)

观察者模式是一种行为型模式,主要用于处理不同对象
之间的交互通信问题。观察者模式中通常会包含两类对象。

一个或多个发布者对象:当有重要的事情发生时,会通知订阅者。
一个或多个订阅者对象:它们追随一个或多个发布者,监听它们的通知,并作出
相应的反应

总结: 1.指定一个发布者
    2.给发布者添加缓存列表,存放回调函数,通知订阅者
    3.发布信息时,发布者遍历缓存表,触发存放的回调函数

监听器Observer和订阅者Watcher

实现简单版Vue的过程,主要实现{{}}、v-model和事件指令的功能

  • 监听器Observer

Observer是一个数据监听器,核心是前面一直谈论的Object.defineProperty(),
对所有属性监听,利用递归来遍历所有的属性值,对其进行Object.defineProperty()操作:

实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性
  • 订阅者Watcher

     Watcher将数据监听器和指令解析器连接起来,数据的属性变动时,执行指令绑定的相应回调函数,如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。
    

Watcher在初始化的时候要将自己添加进订阅者Dep中,如何做到:
已经知道监听器Observer是在get函数执行了添加订阅者Wather的操作的,

所以我们只要在订阅者Watcher初始化的时候触发对应的get函数,去执行添加订阅者操作即可,

那要如何触发get的函数:

只要获取对应的属性值就可以触发了,核心原因就是因为我们使用了Object.defineProperty()进行数据监听。

注意:
我们只要在订阅者Watcher初始化的时候才需要添加订阅者,所以需要做一个判断操作,
因此可以在订阅器上做一下手脚:在Dep.target上缓存下订阅者,添加成功后再将其去掉就可以了。
创建一个watcher.js

指令解析器complie

指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher

Vue对生命周期的理解

生命周期图示

总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。

创建前/后: 在beforeCreated阶段,vue实例的挂载元素 eldataundefinedcreatedvuedata e l 和 数 据 对 象 d a t a 都 为 u n d e f i n e d , 还 未 初 始 化 。 在 c r e a t e d 阶 段 , v u e 实 例 的 数 据 对 象 d a t a 有 了 , el还没有。

载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

更新前/后:当data变化时,会触发beforeUpdate和updated方法。

销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

钩子函数

一个指令定义对象可以提供一下几个钩子函数:

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  • unbind:只调用一次,指令与元素解绑时调用。

    钩子函数的参数(el、binding、vnode、oldVnode):
    
  • el:指令所绑定的元素,可以用来直接操作 DOM 。

  • binding:一个对象,包含以下属性:

    name:指令名,不包括 v- 前缀。
    value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
    oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
    arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
    modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
    
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

注意:除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

vue的双向绑定

Vue的父子组件之间的传值

组件通信

父与子通信

发送: '<son myName='zhangsan'></son>'
接收到json组件:
Vue.component('son',{
      props:['myName'],              
      template:`
       <p>{{myName}}</p>
         `
   }) 

子与父通信

绑定:
methods:{
         handleEvent:function(msg){}
        }
        <son @customEvent="handleEvent"></son>
触发:子组件内部:
this.$emit(‘customEvent’,100);

reference(引用、参考)

帮助在父组件中 得到子组件中的数据、方法。

指定ref属性  ‘<son ref="mySon"></son>’

根据ref得到子组件实例: 
this.$refs.mySon

$parent
this.$parent得到父组件的实例

兄弟组件通信

var bus = new Vue();

接收方:

bus.$on(‘eventName’,function(msg){})

发送方:

bus.$emit(‘eventName’,123);

不相关组件之间传递数据

组件B $emit触发事件:

  import Bus from './bus.js' 
   byBus:function(){
           Bus.$emit('byBus',this.byBusData)
        }

组件A $on接受事件传递数据

 data(){
    },
    created(){
       Bus.$on('byBus',(data)=>{
           this.busData = data
       })
    },

Vue的路由关系

路由模块本质是建立起url和页面之间的映射关系

router路由器
route路由
routes路由数组(路由字典)

路由模块的基本使用
* 引入 vue.js vue-router.js
* 指定一个容器 ‘’
* 创建业务所需要用到的组件类‘var MYLogin = Vue.component()’
* 配置路由字典

const
 myRoutes = [
      {path:'',component:MyLogin},
      {path:'/login',component:MyLogin}
     ];    

new Vue({
       router:myRouter
     })
  • 测试

修改地址栏中的路由地址,测试看加载的组件是否正确

注意事项:

1.先引入vue,再引入插件

2.一定要指定router-view

3.route路由 {path:'',component:}
  routes:路由数组 [] 
  router:路由器,按照指定的路由规则去访问对应的组件 new VueRouter

使用路由模块来实现页面跳转的方式

方法1: 直接修改地址栏
方法2: this.$router.push(‘路由地址’);
方法3: ‘’

完成参数传递

在页面之间跳转的时候,在有些场景下,需要同时指定参数

明确发送方和接收方
list --20--> detail
配置接收方的路由地址
/detail --》 /detail/:index
this.$route.params.index
发送
routerLink to="/detail/20"
this.$router.push('/detail/20')

路由嵌套
在一个路由中,path对应一个component,如果这个component需要根据不同的url再加载其他的component,称之为路由的嵌套
eg:A组件现在需要根据不同的url,加载B组件或者C组件

  给A组件指定一个容器
 <router-view></router-view>
  配置路由词典
   {
    path:'/a',        
    component:A,
    children:[
    {path:'/b',component:B}
    ]
  }

Vue的页面之间传值跳转

路由传值

在跳转页面时,在标签中用‘’标签

this.$router.push({

            name: 'routePage',

            query/params: {

              routeParams: params

            }

          }) 

实用params去传值的时候,在页面刷新时,参数会消失,用query则不会有这个问题。

通过 parent, p a r e n t , chlidren等方法调取用层级关系的组件内的数据和方法

this.$parent.$data.id //获取父元素data中的id

this.$children.$data.id //获取父元素data中的id 

用起来比较灵活,但是容易造成代码耦合性太强,导致维护困难

通过eventBus传递数据

使用前可以在全局定义一个eventBus

window.eventBus = new Vue();
在需要传递参数的组件中,定义一个emit发送需要传递的值,键名可以自己定义(可以为对象)

eventBus.$emit('eventBusName', id);

在需要接受参数的组件重,用on接受该值(或对象)

//val即为传递过来的值

eventBus.$on('eventBusName', function(val) {console.log(val)}) 

最后记住要在beforeDestroy()中关闭这个eventBus

eventBus.$off('eventBusName');

如何去引入组件

VUEX

vuex是一个专门为vue.js设计的集中式状态管理架构,集中存储和管理应用的所有组件状态。

vuex将组件公用数据抽离,在一个公共仓库管理,使得各个组件容易获取(getter)数据,也容易设置数据(setter)。

webpack

webpack搭建vue项目步骤

webpack搭建vue项目步骤

webpack怎么部署 打包过程 优化

创建项目:

mkdir vue-demo 
cd vue-demo

用npm init命令生成package.json文件

npm init

生成package,json文件

引入webpack

npm install webpack --save-dev

在项目中创建webpack.config.js文件

const path = require('path')
module.exports ={
 entry:'./src/main.js',
 output:{
  path:path.resolve(__dirname,'dist'),
  filename:"demo.js"
 }
}

vue的基本构造

1.vue组件的重要选项(属性)

new Vue({
  data:{
      a:1,
      b:[]
},
   methods:{
    doSomething:function(){
       console.log(this.a)
  }
},
watch:{
   'a':function(val,oldVal){
    console.log(val,oldVal)
   }
}
})

data:对象的数据,用对象a,b对HTML中的a,b进行双向绑定,

methods:对象的方法,包括的是方法,针对的是a

watch:进行的是对象监听,针对a进行新值和旧值的监听

2.模板指令(常用的几种)

作用:将HTML和vue连接起来,写在HTML中

  • 数据渲染:v-text、v-html、{{}} (进行自动更新)
<p>{{ a }}</p>
<p v-text="a"></a>
<p v-html="a"></a>
new Vue{
  data:{
      a:1,
      b:[]
  }
})
  • 控制模块隐藏:v-if、v-show

    v-show用css中的display:none来隐藏元素

<p v-if="isShow"></p>
<p v-show="isShow"></p>
new Vue{
  data:{
      isShow: true
  }
})
  • 渲染循环列表 v-for

    HTML中不需要定义多个列表,只需要传入多个数据,则V-for命令会直接对数据的选项列表进行渲染

<div id="app">
    <ul>
        <li v-for="val,key in fruits">
            {{val}}=>{{key}}
        </li>
    </ul>
</div>

document.addEventListener('DOMContentLoaded',function(){
    var vm = new Vue({
        el:'#app',
        data:{
            fruits:['apple','banana','orange','pear']
        }
    });
},false);

这里写图片描述

  • 事件绑定 v-on

    第二行为简写形式,dothis是在methods中获取方法

<button v-on:click="doThis"></button>
<button @click="diThis"></button>
methods:{
  doThis:function(someThing){

  }
}
  • 属性绑定 v-bind

    第一条:对src属性赋值(字符串)

    第二条:简写方式;对对象class进行绑定,isRead是对是否有class的一个判断(布尔值)

    第三条:是一个数组,表示两个class,分别展现data给classA和classB所赋的值(字符串)

    第四条:{classB: isB,classC: isC }中isB和IsC表示classB和classCss是否会展现

<img v-bind:src="imageSrc">

<div :class="{red:isRed}"></div>
<div :class="[classA,classB]"></div>
<div :class="[classA,{classB: isB,classC: isC }]"></div>

vue的简单尝试

1.第一个例子
渲染出多个li标签, 并用true 和false来设定标签的样式

<template>
  <div id="app">
     <h1 v-html="title"></h1>
    <ul>
      <li v-for="item in items" v-bind:class="{finished:item.isFinished}">
         {{item.label}}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  data: function(){
      return{
          title: '<span>?</span>this is a todo list2',
          items: [
            {
                label: 'coding',
                isFinished: false
            },
            {
               label:'walking',
              isFinished: true
            }
          ],
      }
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
.finished{
  text-decoration: underline;
}
</style>

这里写图片描述

  * v-html和 v-text的区别:v-html可以将<span>解析为一个标签;而v-text将<span>解析为字符串即效果为“<span>?</span>this is a todo list2”
  * v-for:将li标签渲染成两个li;v-bind:给li标签添加一个带有下划线的属性,并且下划线的显示

2.第二个例子

显示一个输入框,将输入的值变为一个li列表

<div id="app">
     <h1 v-html="title"></h1>
    <input v-model="newItem" v-on:keyup.enter="addNew"/>
    <ul>
      <li v-for="item in items" v-bind:class="{finished:item.isFinished}" v-on:click="toggleFinish(item)">
         {{item.label}}
      </li>
    </ul>
  </div>
<script>
export default {
  data: function(){
      return{
          title: '<span>?</span>this is a todo list2',
          items: [

          ],
        newItem:''
      }
  },
  methods:{
     toggleFinish: function (item) {
        console.log(item.isFinished = !item.isFinished)
     },
    addNew: function () {
      this.items.push({  //实现输入一个新值,在下方出现
        label:this.newItem,
        isFinished: false
      });
      this.newItem=''
    }
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
.finished{
  text-decoration: underline;
}
</style>

这里写图片描述

  • v-on:click 添加一个绑定事件method–>toggleFinished(item),实现点击一次下划线消失,再点击一次又出现
  • v-model:表单控件双向绑定
  • input–>v-on:methods–>addNew获取并打印出newItem的值

localstorage存储todolist

输入的内容在刷新后不会消失,并且获取到页面上

<div id="app">
    <h1 v-html="title"></h1>
    <input v-model="newItem" v-on:keyup.enter="addNew"/>
    <ul>
      <li v-for="item in items" v-bind:class="{finished:item.isFinished}" v-on:click="toggleFinish(item)">
        {{item.label}}
      </li>
    </ul>
  </div>
import Store from './store'  //es6写法
  console.log(Store);
  export default {
    data: function(){
      return{
        title: '<span>?</span>this is a todo list2',
        items: Store.fetch(),
        newItem:''
      }
    },
    watch:{
       items:{
            handler:function(items){
            Store.save(items)
        },
         deep:true
    }
  },
    methods:{
      toggleFinish: function (item) {
        console.log(item.isFinished = !item.isFinished)
      },
      addNew: function () {
        this.items.push({
          label:this.newItem,
          isFinished: false
        });
        this.newItem=''
      }
    }
  }

store.js

const STORAGE_KEY='todos-vuejs';
export default {
  fetch:function () {
    return JSON.parse(window.localStorage.getItem(STORAGE_KEY) || '[]')
  },
  save:function (items) {
    window.localStorage.setItem(STORAGE_KEY,JSON.stringify(items))
  }
}

这里写图片描述

* 在App.vue同级处新建一个store.js文件,作用是作为一个存储器,将输入的内容存储起来,防止刷新页面的时候丢失
* watch 对象:观察方法,handler 为深层赋值方法,给store传入items
划分组件

vue模板


1.html模板

2.字符串标签

template字符串

<script type="x-template" id="str">
        <p>
            我是一个标签
        </p>
    </script>
</head>
<body>
  <div id="box">

  </div>
</body>


document.addEventListener('DOMContentLoaded',function(){
   var vm = new Vue({
       el:'#box',
       template:'#str'
   }) ;
},false);

这里写图片描述

从demo图中可以看出,box中添加了script中的p标签,p标签替换了box中的内容

<body>
  <template id="tem">
      <p>我是template</p>
  </template>
  <div id="box">

  </div>
</body>

这里写图片描述

这个demo中,template标签的p标签代替了div标签

3.render函数

<style type="text/css">
        .bg{
            background-color: yellow;
        }
    </style>
</head>
<body>
<div id="box">

</div>

 document.addEventListener('DOMContentLoaded',function(){
        var vm = new Vue({
            el:'#box',
            render(createrElement){
                return createrElement(//调用一个函数
                    "ul",
                    {
                        class:{bg:true},//给UL添加dom属性和绑定事件等,相当于v-bind:class="{bg:true}"
                        style:{fontSize:"50px"},
                        attrs:{
                            abc:"Datura"
                        },
                        domProps:{
                            innerHTML:"<li>我是HTML</li>"//这个优先级比下面的createrElement高,此时下面效果无效
                        }
                    },
                    [
                        createrElement("li",1),
                        createrElement("li",2),
                        createrElement("li",3),

                    ]
                );
            }
        });
    },false);

vue的数据同步


1.数据绑定

<div id="app">
  {{ message }}
</div>


var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

2.双向绑定

<div id="app">
    {{message}}
    <br>
    <input type="text" placeholder="请输入" v-model="message"/>
</div>



document.addEventListener('DOMContentLoaded',function () {
    //vm实例
    var vm = new Vue({
        el: '#app',  //挂载元素
        data:{
            message:'hello,Datura!!!'
        }
    });
},false);

自定义指令


1.全局指令

可以让所有人使用

<div class="app">
    <div v-color="colorStatus">我是一个普通div元素</div>
</div>

document.addEventListener('DOMContentLoaded',function (){
    Vue.directive('color',function(el,binding){
       console.log(el);
       console.log(binding);
       el.style.backgroundColor = 'lawngreen';
    });
    var vm = new Vue({
       el:'.app',
        data:{
           colorStatus:true
        }
    });
},false);

这里写图片描述

2.局部指令

当前组件可用

 <script type="text/javascript">
        document.addEventListener('DOMContentLoded',function(){
           var vm = new Vue({
               el:'.app',
               data:{
                   colorStatus:true
               },
               directives:{
                   'color':function(el,binding){
                       el.style.backgroundColor = 'green';
                   }
               }
           }) ;
        },false);
    </script>
</head>
<body>
    <div class="app">
        <div v-color="colorStatus">我是一个普通div元素</div>
    </div>
</body>
  • 没有运行成功,找不到原因。。。心塞
  • 比较全局指令和局部指令,局部指令多有了一个directives,但是仅仅是把el和binding封装在里面
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值