这是@尚春实现的MVVM,使用定时器轮询,只支持{{}}与input.value的修改。

这只能算是一个玩具,真正的MVVM需要有更复杂的扫描机制,JS解析器,双向绑定链什么的。

<!DOCTYPE html>
<html>
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title> </head>
<body>
<div data-component="input">
<template>
<input type="text" name="username" tb-model="username" value="" />
<span>{{ username }}</span>
</template>
</div>
<script>
var DIRECTIVE_ATTR_MODEL = 'tb-model',
regMustache = /\{\{\s*(\w+)\s*\}\}/g,
slice = Array.prototype.slice; function boot() {
var components = slice.call(document.querySelectorAll('[data-component]'), 0);
components.forEach(function (el) {
var component = el.getAttribute('data-component');
bootComponent(el, window[component + 'Controller']);
});
} function bootComponent(el, controller) {
var $scope = {},
elFrag = el.querySelector('template').content.cloneNode(true);
traverse(elFrag, $scope);
el.appendChild(elFrag);
controller($scope);
} function traverse(root, $scope) {
for (var el = root.firstChild; el; el = el.nextSibling) {
parseElement(el, $scope);
if (el) {
traverse(el, $scope);
}
}
} function parseElement(el, $scope) {
if (el.nodeType === 1) {
// element
if (el.hasAttribute(DIRECTIVE_ATTR_MODEL)) {
var model = el.getAttribute(DIRECTIVE_ATTR_MODEL);
el.removeAttribute(DIRECTIVE_ATTR_MODEL);
el.addEventListener('input', function () {
$scope[model] = this.value;
});
}
} else if (el.nodeType === 3) {
// text node
var text = el.textContent,
tpl = [],
lastIndex = 0,
match = regMustache.exec(text);
while (match) {
tpl.push(text.substring(lastIndex, regMustache.lastIndex - match[0].length));
tpl.push({
type: 'var',
content: match[1]
});
lastIndex = regMustache.lastIndex;
match = regMustache.exec(text);
}
watch($scope, function () {
text = '';
tpl.forEach(function (item) {
text += typeof item === 'string' ? item : $scope[item.content];
});
el.textContent = text;
});
}
} function watch($scope, cb) {
var old = _.cloneDeep($scope),
timer;
timer = setInterval(function () {
if (!_.isEqual($scope, old)) {
cb($scope, old);
old = _.cloneDeep($scope);
}
}, 50);
} function inputController($scope) {
$scope.username = 'spring';
} boot();
</script>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>

</head>
<body>
<div data-component="input">
<template>
<input type="text" name="username" tb-model="username" value="" />
<span>{{ username }}</span>
</template>
</div>
<script>
var DIRECTIVE_ATTR_MODEL = 'tb-model',
regMustache = /\{\{\s*(\w+)\s*\}\}/g,
slice = Array.prototype.slice;

function boot() {
var components = slice.call(document.querySelectorAll('[data-component]'), 0);
components.forEach(function (el) {
var component = el.getAttribute('data-component');
bootComponent(el, window[component + 'Controller']);
});
}

function bootComponent(el, controller) {
var $scope = {},
elFrag = el.querySelector('template').content.cloneNode(true);
traverse(elFrag, $scope);
el.appendChild(elFrag);
controller($scope);
}

function traverse(root, $scope) {
for (var el = root.firstChild; el; el = el.nextSibling) {
parseElement(el, $scope);
if (el) {
traverse(el, $scope);
}
}
}

function parseElement(el, $scope) {
if (el.nodeType === 1) {
// element
if (el.hasAttribute(DIRECTIVE_ATTR_MODEL)) {
var model = el.getAttribute(DIRECTIVE_ATTR_MODEL);
el.removeAttribute(DIRECTIVE_ATTR_MODEL);
el.addEventListener('input', function () {
$scope[model] = this.value;
});
}
} else if (el.nodeType === 3) {
// text node
var text = el.textContent,
tpl = [],
lastIndex = 0,
match = regMustache.exec(text);
while (match) {
tpl.push(text.substring(lastIndex, regMustache.lastIndex - match[0].length));
tpl.push({
type: 'var',
content: match[1]
});
lastIndex = regMustache.lastIndex;
match = regMustache.exec(text);
}
watch($scope, function () {
text = '';
tpl.forEach(function (item) {
text += typeof item === 'string' ? item : $scope[item.content];
});
el.textContent = text;
});
}
}

function watch($scope, cb) {
var old = _.cloneDeep($scope),
timer;
timer = setInterval(function () {
if (!_.isEqual($scope, old)) {
cb($scope, old);
old = _.cloneDeep($scope);
}
}, 50);
}

function inputController($scope) {
$scope.username = 'spring';
}

boot();
</script>
</body>
</html>

运行代码

一个简单的MVVM雏形的更多相关文章

  1. 230行实现一个简单的MVVM

    作者:mirone链接:https://zhuanlan.zhihu.com/p/24451202来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. MVVM这两年在前端届 ...

  2. 如何实现一个简单的MVVM框架

    接触过web开发的同学想必都接触过MVVM,业界著名的MVVM框架就有AngelaJS.今天闲来无事,决定自己实现一个简单的MVVM框架玩一玩.所谓简单,就是仅仅实现一个骨架,仅表其意,不摹其形. 分 ...

  3. 一个简单的 MVVM 实现

    简介 一个简单的带有双向绑定的 MVVM 实现. 例子 使用 新建一个 ViewModel 对象, 参数分别为 DOM 元素以及绑定的数据即可. 指令 本 MVVM 的指令使用 data 数据, 即 ...

  4. 撸一个简单的MVVM例子

    我个人以为mvvm框架里面最重要的一点就是VM这部分,它要与Model层建立联系,将Model层转换成可以被View层识别的数据结构:其次也要同View建立联系,将数据及时更新到View层上,并且响应 ...

  5. JavaScript 实现一个简单的MVVM前端框架(ES6语法)

    前言 随着前端各大框架的崛起,为我们平时的开发带来了相当的便利,我们不能一直停留在应用层面,今天就自己动手实现一个乞丐版的MVVM小框架 完整代码github地址 效果 html代码 <div ...

  6. 基于vue实现一个简单的MVVM框架(源码分析)

    不知不觉接触前端的时间已经过去半年了,越来越发觉对知识的学习不应该只停留在会用的层面,这在我学jQuery的一段时间后便有这样的体会. 虽然jQuery只是一个JS的代码库,只要会一些JS的基本操作学 ...

  7. 用js实现一个简单的mvvm

    这里利用的object.defineproperty() 方法; <input     id='input'><p id='p'><p/>js: const dat ...

  8. MVVM之旅(1)创建一个最简单的MVVM程序

    这是MVVM之旅系列文章的第一篇,许多文章和书喜欢在开篇介绍某种技术的诞生背景和意义,但是我觉得对于程序员来说,一个能直接运行起来的程序或许能够更直观的让他们了解这种技术.在这篇文章里,我将带领大家一 ...

  9. 【UWP开发】一个简单的Toast实现

    Toast简介 在安卓里Toast是内置原生支持,它是Android中用来显示显示信息的一种机制.它主要用于向用户显示提示消息,没有焦点,显示的时间有限,过一定的时间就会自动消失.在UWP中虽然没有原 ...

随机推荐

  1. linux 命令 --if

    if else-if else 语法格式: if condition1 then command1 elif condition2 then command2 else commandN fi 例如: ...

  2. Hadoop1.1.2伪分布式安装

    一.安装前准备设置Linux的静态IP修改VirtualBox的虚拟网卡地址修改主机名把hostname和ip绑定关闭防火墙:service iptables stop二.SSH免密码登陆生成秘钥文件 ...

  3. 对象存储在什么地方(java编程思想)

    用引用操作对象.创建了一个引用,需要进行初始化(与事物进行关联),才能正常使用.new将引用于对象进行关联 对象存储到什么地方? 程序运行时,对象是怎么进行放置安排的呢?特别是内存是怎么分配的呢?对这 ...

  4. java远程下载文件到本地

    方法一 ** * 下载远程文件并保存到本地 * * @param remoteFilePath-远程文件路径 * @param localFilePath-本地文件路径(带文件名) */ public ...

  5. Sqlserver 按照时间段统计数据

    WITH t1 ( [hour], title ) , ' 0:00:00--- 1:00:00' UNION ALL , ' 1:00:00--- 2:00:00' UNION ALL , ' 2: ...

  6. 【idea】idea的常规设置

    [一]在输入框输入字符,自动提示代码 File->Power Save Mode  去掉“对号” [二]自动代码提示的快捷键设置 (1)不区分大小写提示 (2)修改快捷提示快捷键.将basic= ...

  7. Packer 基本试用

    安装 使用mac 系统 https://www.packer.io/downloads.html 配置环境变量 可选 sudo nano ~/.bash_profile export PATH=$PA ...

  8. BinaryFormatter、SoapFormatter、XML3种序列化

    序列化和反序列化我们可能经常会听到,其实通俗一点的解释,序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用.我想最主要的作用有:1.在进程下次 ...

  9. Angular 安装

    1.angular安装 npm  install -g angular 2. 显示angular安装路径 npm config ls 3. angular 双向绑定 <!DOCTYPE html ...

  10. WCF揭秘学习笔记(2):数据表示

    背景知识 WCF提供了一种语言为软件通信建模,称作服务模型.使用更底层的编程架构提供的类可以从这种语言建立的模型中生成可用的通信软件. 在服务模型使用的语言中,负责通信的软件部分称为服务(servic ...