Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue2.0 中 render 和 template 疑惑点 #3

Open
pfan123 opened this issue Jun 30, 2017 · 2 comments
Open

Vue2.0 中 render 和 template 疑惑点 #3

pfan123 opened this issue Jun 30, 2017 · 2 comments

Comments

@pfan123
Copy link
Owner

pfan123 commented Jun 30, 2017

从 Vue 升级到2.0之后,多了采用jsx方式渲染生成HTML模版,还有一种就是一直沿用的 template 字符串拼接方式生成模版,但其实隐含的还有 直接去挂载手动写入模版,Vue 的功能很强大多种方式有时也让我们感到到很😅

Vue2.0 生成 HTML 方式:

  • 1.使用 render 函数jsx方式渲染生成HTML模版
  • 2.使用 template 字符串拼接方式生成模版
  • 3.采用自定义标签,内嵌到 Vue 根实例挂载点(自定义标签影响html语义化,不推荐,但其实这个算是vue 1.0 采用 es5 写法遗留问题未借用babel)

注意: 对于挂载实例 不是采用 render 方式拼接模版,webpack 打包 vue 会报错,主要是由于webpack选择 vue 版本问题,详见 https://github.com/vuejs-templates/webpack/issues/215,[2.0 Changes #2873](vuejs/vue#2873)

警告错误 [Vue warn]: You are using the runtime-only build of Vue where the template option is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

在解释这些之前,我们先搞清楚明白,组件 component 与 根实例 new Vue() 的关系:

创建 Vue 的根实例

const vm = new Vue({
  // 选项对象

  data: {},
  template: '<my-component></<my-component>',
  //render: (myComponent) => {
 	   return createElement(myComponent)
 	},

  components: {
  	"my-component": MyComponent 
  },

  created () => {

  },

  mounted () => {

  },

  methods () => {

  }

})

一个 Vue 实例其实正是一个 MVVM 模式中所描述的 ViewModel - 因此在文档中经常会使用 vm 这个变量名。
在实例化 Vue 时,需要传入一个选项对象,它可以包含数据、模板、挂载元素、方法、生命周期钩子等选项。

创建 component 组件

可以扩展 Vue 构造器,从而用预定义选项创建可复用的组件构造器(这个是官方说法,比较绕口),其实说白了,组件可以理解为继承于 Vue 构造器,与跟实例 vm 存在细微的差别对数据指针data更改。

//继承Vue 构造器,创建组件,区别修改data指针,跟实例 data: {},组件 data () {return {}} 
const MyComponent = Vue.extend({
  // 扩展选项对象
})

// 所有的 `MyComponent` 实例都将以预定义的扩展选项被创建,实例组件可以直接 data: {}, 没有指针问题,不会影响其他组件
const myComponentInstance = new MyComponent({
  data: {}
})

注册 component 组件

组件全局注册

// 要使用这个组件构造器做的组件,需要用 Vue.component(tag, consturctor) 注册--全局注册,注册在根实例上的,全局可以直接使用
// Vue.component('my-component', MyComponent)

注意:对于统一性、共用性组件,建议采用组件全局注册方式,如 <ant-img src = "" v-on:error="_errorReport()" v-on:load="_loadReport"></ant-img>替代image标签进行统一上报处理。

组件局部注册

// vue 创建组件默认,使用构造器,然后实例生成组件
const MyComponent = Vue.extend({
  
})

const myComponentInstance = new MyComponent({
	data: {},
	components: {
	  "my-component": MyComponent  //组件局部注册,注册在子组件上的
	}
})

有了以上知识之后,基本对vue的实例,组件思路有了整理的了解,那接下来理解 Vue2.0 生成 HTML 方式。

render 函数jsx方式渲染生成HTML模版

字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。render 函数接收一个 createElement 方法作为第一个参数用来创建 VNode

//根实例挂载
const vm = new Vue({
	//virtul Dom 方案渲染模版
	render: h => h(APP)

	//render: (createElement) => {
	//	 return createElement(APP)
	//}	
}).$mount('#app')

createElement 函数中生成模板:

createElement(
  // {String | Object | Function}
  // 一个 HTML 标签,组件选项,或一个函数
  // 必须 Return 上述其中一个
  'div',
  // {String | Array}
  // Children VNodes, built using `createElement()`,
  // or simply using strings to get 'text VNodes'. Optional.
  [
    'Some text comes first.',
    createElement('h1', 'A headline'),
    createElement(MyComponent, {
      props: {
        someProp: 'foobar'
      }
    })
  ]
)

template 字符串拼接方式生成模版

    // Vue.extend()组件构造器
    const MyComponent = Vue.extend({
      template: '<div>大家好,{{msg}}我来了</div>',
      data: function () {
        return {
          msg: 'Hello!'   //组件构造器生成的组件data数据需要return 返回,而实例new Vue()不需要(主要是处理指针问题)
        }
      },
      created: function(){
        console.log("组件开始创建")
      }
    })

    const vm = new Vue({
    	//template是字符串模版拼接方案渲染模版
    	template: '<my-component></my-component>',
	    components: {
	       "my-component": MyComponent  //实例局部注册组件
	    },
	    created(){
	    	console.log("开始创建")
	    }

    })

采用自定义标签,内嵌到 Vue 根实例挂载点获取模版

index.html

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
  <meta name="author" content="@pfan"/>
</head>

    <!-- S 左侧导航内容 -->
    <div vm-mod = "sideLeftNav">
      <my-component></my-component>
    </div>
    <!-- E 左侧导航内容 -->

    <!-- 这里填写路径是输出的路径 相对于dist输出路径 -->
    <!-- <script src="./app.js"></script> -->
  </body>
</html>
 

app.js

import Vue from 'vue'

var MyComponent = Vue.extend({
  template: '<div>大家好,{{msg}}我来了</div>',
  data: function () {
    return {
      msg: 'Hello!'  
    }
  },
  created: function(){
    console.log("组件开始创建")
  }
})

//全局注册,不需要在组件做局部注册
Vue.component('my-component', MyComponent)

const vm = new Vue({
	el: '[vm-mod="sideLeftNav"]', 

	//由于组件是全局注册,所以不需要局部注册,可直接使用
	components: {
	//	"my-component": MyComponent  //实例局部注册组件
	}
})

ps: 注意,自定义标签的这种模版方式不推荐使用,影响html语义化。

总结,通过以上的例子,我们理清了,组件与 Vue 根实例的关系, 以及挂载点,生成 html 的方式,最后更好的扩展优化可以深入做vue组件直出方案 prerender-spa-plugin 做简单直出。

参考资料:

官方 Vue.js 教程
极客 Vue.js 教程
Vue 组件 data 为什么必须是函数?

@bi-kai
Copy link

bi-kai commented Sep 27, 2018

// 所有的 MyComponent 实例都将以预定义的扩展选项被创建
const myComponentInstance = new MyComponent({})

请问,这句是什么意思?vue内部哪个阶段执行的?

@pfan123
Copy link
Owner Author

pfan123 commented Mar 26, 2019

@bi-kai const myComponentInstance = new MyComponent({}) 这里是实例化组件,并不是那个生命周期执行,挂载在 vue 根实例,complier之后才会有生命周期

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants