vue與react組件的思考

前言

我最一開始是先學的react,而後也就前段時間開始學習vue,一開始給個人感覺是二者很類似,react給個人感受是靈活vue是一種死板的感受。爲何有這種感受呢,react有一種很強烈的慾望,all in js只要可以用夠js寫的,就全用js寫,因此一切都很靈活,jsx很酷,高階組件牛逼,es7的裝飾器也是能夠玩的飛起。反觀vue,搞的.vue單文件仍是儘可能保留原來前端開發的模式,留下了templatescriptstyle三個最基本的東西,其實內部運做應該仍是和react相似。html

react

react看的各類道聽途說的文章,這玩意大概是怎麼玩的呢?簡單的說jsx被解析成createElement的方法,裏面傳到參數啊什麼的就是告訴react怎麼渲染之類,而後方法返回一個虛擬dom,大概是這麼搞的,具體細節我也不是太懂。前端

vue

vue一開始讓我挺暈的,官網的學習教程和通常寫的項目不太同樣,官網教程的例子沒有單文件,全是在選項對象中加入一個template屬性,通常的項目開發的都是用的.vue的單文件。一開始我是沒太理解.vue這文件究竟是怎麼玩,只是按着這樣寫,不理解原理好像也可以基本完成本身想要的效果。vue

最近看了一些文章以及看了好幾遍官網的api官網的api仍是頗有必要每個都看一遍的,以前大體看一遍感受好多東西都沒有見到過,別人代碼看多了,發現不少沒用的api仍是很強的。下面講講我對vue的一些理解。node

vue是怎麼玩的呢?每個vue組件都是一個Vue實例,這樣說也不是很準確,應該每個本身寫的組件都是經過調用Vue.extend繼承Vue後擴展出來的新的類的實例,想想怎麼定義一個vue組件,就是調用了Vue.component方法react

// 註冊組件,傳入一個擴展過的構造器
Vue.component('my-component', Vue.extend({ /* ... */ }))

// 註冊組件,傳入一個選項對象 (自動調用 Vue.extend)
Vue.component('my-component', { /* ... */ })

// 獲取註冊的組件 (始終返回構造器)
var MyComponent = Vue.component('my-component')

通常狀況下咱們寫的.vue單文件暴露出來的就是一個選項對象,這個方法的內部自動調用了Vue.extend。因此.vue單文件本質上是vue-loader去把<template></template>裏的內容轉成字符串形式,塞到<scirpt></script>裏面的export default {}的對象裏面的template去,固然了,這尚未完,template屬性裏面的字符串也能夠說是一種糖,vue內部是要調用Vue.compile去作一次轉換,最終把template的值轉換成render,這個屬性的值是一個方法,這裏就和react統一了,用是有個同名的函數createElement去生成Vnode。因此在選項對象中,能夠不給出template屬性而是給出render屬性,同時存在templaterender的時候會忽視templategit

看看官網render用法:github

var getChildrenTextContent = function (children) {
  return children.map(function (node) {
    return node.children
      ? getChildrenTextContent(node.children)
      : node.text
  }).join('')
}

Vue.component('anchored-heading', {
  render: function (createElement) {
    // create kebabCase id
    var headingId = getChildrenTextContent(this.$slots.default)
      .toLowerCase()
      .replace(/\W+/g, '-')
      .replace(/(^\-|\-$)/g, '')

    return createElement(
      'h' + this.level,
      [
        createElement('a', {
          attrs: {
            name: headingId,
            href: '#' + headingId
          }
        }, this.$slots.default)
      ]
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})

看的出來這種直接寫render比起template要麻煩的多,因此爲了簡化這種寫法就搞出來了一個jsx寫法,這裏又和react又統一了。api

jsx用法:iview

import AnchoredHeading from './AnchoredHeading.vue'

new Vue({
  el: '#demo',
  render: function (h) {
    return (
      <AnchoredHeading level={1}>
        <span>Hello</span> world!
      </AnchoredHeading>
    )
  }
})

一個需求引起的思考

一般咱們寫reactvue都是一個寫一個組件customComp,而後在別的組件要用的時候都是直接<customComp/>寫進去的,可是有的組件就不能這麼作了,好比一個提醒的message組件,我但願在react中是這樣調用,像是一個工具類函數通常使用:dom

import message from 'message.js'
import React from 'react'

class XXXcomponent extends React.Component{
    ...
    componentDidMount(){
        message.info({
            type:'success',
            text:'hello react!'
        })
    }
}

vue中我但願是這樣的調用的:

{
    mounted(){
        this.$message({
            type:'success',
            text:"hello vue!"
        })
    }
}

在看了一些三方庫的這種組件的實現方式,來回折騰了一段時間,對reactvue理解的更深了一些。

vue的實現

先拿vue說,先寫一個message.vue的組件文件,而後在index.js文件中把這個message.vue文件import進來,你能夠試着打印下這個vue文件長得什麼樣,其實前面也分析過了,其實引進來的就是一個選項對象,並且<template></template>標籤的內容也被弄成了render屬性了,前面也鋪墊過了vue.extend,這裏把引入的選項對象傳入vue.extend中就返回了一個擴展過的Vue類了,而後咱們手動去new一個message的組件實例出來,能夠傳入一個propsData就能把數據傳給到組件內部的prop中去,打印下實例就會發現定義在.vue文件中的dataprop之類的都有,這個時候咱們只是實例化了一個實例,其實在document上是找不到這個節點的,只須要最後在實例上調用$mount(el),就能把實例掛載到document上去了。直接修改實例上data裏面定義的值,會發現也是響應的,至此這個message組件咱們可以手動去控制這個組件了,具體細節該怎麼暴露出api來個外部調用就不說了。

//僞代碼
import message from 'message.vue'
import Vue from 'vue'

const Constructor = Vue.extend(message) //擴展出一個新的類

const options = {
    innerProps:"inner props"
}

const instance = new Constructor({propsData:options})  //建立一個實例,也能夠傳給一個props

instance.$mount(document.body) //組件掛在body下

//若是組件內部methods有方法,實例就能直接調用

// instance.innerFunction()

react實現

大致上是和vue相似,有幾個地方有變化,引進來的組件,由於是用class extends React.Component的形式寫的,看的出來已是擴展過react後組件類了,直接去new就能拿到實例了,或者是用React.createElement傳入組件拿到虛擬dom。和vue不一樣的事,vue有個$mount方法幫助掛載組件到指定的位置,在react中要用到react-dom裏面的render方法,傳入前面拿到的虛擬dom以及要掛載的位置,這個方法會返回這個組件實例,這個時候就能夠調用組件實例的setState方法去作一些事情了。

總結

reactvue隨便用用帶仍是挺簡單的,個人觀點是api文檔只能教會你70%的東西,可是你有了這70%的功力,大部分的東西基本都沒什麼問題,可是文檔以外的30%,每每是最難學的,可能須要剝開vuereact簡單易用的外表,來回看官方文檔,每次都能有新的體會,翻看第三方優秀的組件庫是最佳學習的方案,深刻地去理解內部原理才能真正的掌握。

這種組件函數式用法在個人fantastic-carnival(一個博客系統)中有體現:
其中有一個loadingBar組件是一個加載條的組件,參考的是iview組件庫中的vue實現,同時我用react也實現了一遍。

參考資料

  1. vue組件思考
  2. vue官網渲染函數
相關文章
相關標籤/搜索