Note
  • Introduction
  • JS
    • JS / JQuery 代码、框架收藏
    • 用Mock.js + AngularJS来提高开发效率
    • 在JavaScript中监听 IME 键盘输入事件
    • 如何组织大型JavaScript应用中的代码?
    • 深入理解javascript原型和闭包
      • 1. 一切都是对象
      • 2. 函数和对象的关系
      • 3. prototype原型
      • 4. 隐式原型
      • 5. instanceof
      • 6. 继承
      • 7. 原型的灵活性
      • 8. 简述【执行上下文】上
      • 9. 简述【执行上下文】下
      • 10. this
      • 11. 执行上下文栈
      • 12. 简介【作用域】
      • 13. 【作用域】和【上下文环境】
      • 14. 从【自由变量】到【作用域链】
      • 15. 闭包
      • 16. 补充:上下文环境和作用域的关系
    • AngularJS
      • AngularJS开发一些经验总结
      • AngularJS Controller 间通信机制
      • AngularJS 中的一些坑
      • 如何解决AngularJs在IE下取数据总是缓存的问题
      • AngularJS之$timeout指令
      • angular 代码日记
      • AngularJS Directive 隔离 Scope 数据交互
      • 在Angular指令中使用NgModelController做数据绑定
      • AngularJS的ngTransclude
      • 使用Angularjs的ng-cloak指令避免页面乱码
      • Directive - Compile vs. Link
    • NodeJS
      • npm的配置管理及设置代理
    • Angular
      • Angular2 - Control Validation on blur
      • Angular2 - how to call component function from outside the app
  • Go
    • How to Test Local Changes with Go Mod
  • Java
    • Java中根据字体得到字符串高度和长度
    • JAVA 判断一个字符串是不是一个合法的日期格式
    • JVM上的随机数与熵池策略
    • tomcat7+jdk的keytool生成证书 配置https
    • Spring
      • SpringMVC中用@ParamVariable传递的参数包含斜杠(/)时,匹配不了报404错误的解决方案
      • SpringMVC 中HttpMessageConverter简介和Http请求415 Unsupported Media Type的问题
      • Spring Boot 打包,分离依赖jar,配置文件
      • SpringBoot启动后 Stopping service [Tomcat]
      • spring-boot打包时排除第三方依赖
    • 第一个Eclipse插件
    • Eclipse 使用技巧
    • HighChart利用servlet导出中文PNG图片乱码问题解决
    • JDK中文字体在Linux操作系统的设置方案
    • Shiro
      • Shiro-Authentication(身份验证)
      • Shiro-Authorization(授权)
    • 详谈再论JAVA获取本机IP地址
  • Python
    • pip国内镜像源的配置
  • Linux
    • Shell脚本 bad interpreter:No such file or directory & /bin/bash^M: bad interpreter错误解决方法
    • 10个重要的Linux ps命令实战
    • Linux 下执行定时任务 crontab 命令详解
    • CentOS 7.x设置自定义开机启动,添加自定义系统服务
    • CentOS 7 下使用 Firewall
    • 在Ubuntu 12.04安装和设置SSH服务
    • 配置CENTOS YUM更新源
    • Linux下终端利器tmux
    • scp命令
    • Linux系统管理常用命令
    • 让你提升命令行效率的 Bash 快捷键 [完整版]
    • SELinux
    • Linux下 RabbitMQ的安装与配置
    • SELinux下更改mysql端口
    • centos 7 升级后yum install出现Exiting on user cancel
    • Linux Shell 通配符、元字符、转义符使用实例介绍
  • Other
    • Docker
      • Docker Proxy
    • Swagger
      • Spring MVC 集成 Swagger
    • Maven
      • maven plugin的execution出错
      • nexus repair或update index 没反应 速度慢 手动配置nexus index
      • nexus 搭建 maven 私服
      • Maven类包冲突终极解决小技若干
      • org.codehaus.plexus.archiver.jar.Manifest.merge(org.codehaus.plexus.archiver.jar.Manifest)
      • Maven 生命周期
      • wagon-maven-plugin
      • Maven中-DskipTests和-Dmaven.test.skip=true的区别
    • MySQL
      • is not allowed to connect to this MySQL server 解决办法
      • MySQL备份--mysql dump
      • MySQL启动中 InnoDB: Error: log file ./ib_logfile0 is of different size 0 5242880 bytes 的问题
      • MySQL修改root密码的多种方法
      • MySQL长事务导致的Table Metadata Lock
      • com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
      • 解决mysql插入数据时出现Incorrect string value: '\xF0\x9F...' for column 'name' at row 1的异常
    • HTTP
      • HTTP 协议中的 Transfer-Encoding
      • 四种常见的 POST 提交数据方式
      • HTTP 请求头中的 X-Forwarded-For
      • 传统轮询、长轮询、服务器发送事件与WebSocket
    • Raspberry
      • 系统安装配置
    • VIM
      • vim常用配置
      • 在vim中使用查找命令查找指定字符串
      • Vim缩进有关的设置总结
    • Git
      • github 同步一个 fork
      • Git 如何 clone 非 master 分支的代码
      • git提示error setting certificate verify locations解决办法
      • git设置和取消代理
      • How to Delete Commit History in Github
      • Windows下使用Beyond Compare作为git的比对与合并工具
    • 解决 Virtualbox 共享文件夹 cannot create symlink error 问题
    • nginx 403 forbidden 二种原因
    • VirtualBox的四种网络连接方式
    • 在Windows的CMD中如何设置支持UTF8编码?
    • nginx使用ssl模块配置HTTPS支持
    • 怎么查看WINDOWS端口被哪个程序占用
    • VMWare 随系统启动指定虚拟机
    • 使用命令行启动VirtualBox虚拟机
    • 该死的^M
    • install home-assistant mosquitto-broker and node-red on android
    • SSH原理与运用:远程登录、远程操作与端口转发
    • SVN mime-type 笔记
    • VirtualBox虚拟机网络配置(NAT + Host-only - Bridged)
    • VirtualBox绿色版的桥接网卡驱动安装
    • OAuth的改变
    • MavenActionUtil.getMavenProject(e.getDataContext()) is Null when developing a intellij plugin
    • Cygwin的安装和配置apt-cyg源
    • Zookeeper运维常用四字命令
    • svn sqlite[S11]: database disk image is malformed
Powered by GitBook
On this page
  • transclued的定义
  • 官方示例及解释
  • 使用compile函数的transclude参数
  • 在controller里注入$transclude

Was this helpful?

  1. JS
  2. AngularJS

AngularJS的ngTransclude

transclued的定义

Transclude 好像并不是一个英语单词,有道词典没有,百度翻译的意思是嵌入的意思。transclude 在 angularjs 的自定义 directive 中是比较常见的一个东西,所以非常有必要了解一下。

我们首先看下官方api对 ng-transclude 的解释:

Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion. Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.

官方示例及解释

<div ng-controller="ctrl">
    <input ng-model="title"></br>
    <textarea ng-model="text"</textarea></br>
    <pane title="{{title}}">
      <p class="content">{{text}}<p>
    </pane>
</div>

这里的 pane 是一个自定义 directive,标签里还有一个表达式,这个指令的目的是显示 input 中输入 title,和 textarea 中输入的 text,当然是按照一定的 dom结构 显示。看下 pane 是如何实现:

app.directive('pane', function() {
    return {
      restrict: 'E',
      transclude: true,
      scope: {
          title:'@'
      },
      template:
            '<div style="border: 1px solid black;">' +
                '<div style="background-color: gray">{{title}}</div>' +
                '<div ng-transclude></div>' +
            '</div>'
    };
});

这个例子的结果生成的 dom结构 是这样的:

<div style="border: 1px solid black;">
    <div style="background-color: gray">我是标题</div>
    我是内容
</div>

有个这样结果我想你就看明白了。原来模板中的 <div ng-transclude></div> 最后会被 <pane></pane> 标签里的表达式内容所替换。这是就是 transclude 的用途。 我们回过头再来看 ng-transclude 的定义:

  • ng-transclude 指明的是一个插入的位置

  • 指令中标签里的元素都会先删除然后被嵌入包含后的内容所替换

这个例子够简单,这也是最基础的用法,我们再来看下高级一点的用法。我们对上面的例子进行扩充,加上了类型和时间:

<div ng-controller="Ctrl">
    <input ng-model="title"><br>
    <input ng-model="type"><br>
    <input ng-model="time"><br>
    <textarea ng-model="text"></textarea> <br/>
    <pane title="{{title}}">
        <span class="time">time</p>
        <p class="type">{{type}}<p>
        <p class="content">{{text}}<p>
    </pane>
</div>

最终的目的是这样的:

<div style="border: 1px solid black;">
    <div style="background-color: gray">
        我是标题<span class="time">我是时间</span>
    </div>
    <p class="type">我是分类</p>
    <p class="content">我是内容</p>
</div>

光一个 ng-transclude 是不行的,当然你也可以像 title 那样传参,但现在是在学习 transclude,没有 transclude 还学个毛啊。我们有两种方法可以实现这个目的。

使用compile函数的transclude参数

先看 pane 的 directive 代码:

app.directive('pane', function() {
    return {
        restrict: 'EA',
        template:
            '<div style="border: 1px solid black;">' +
                '<div class="title" style="background-olor: gray">{{title}}</div>' +
            '</div>',
        replace: true,
        transclude: true,
        compile: function(element, attrs, transcludeFn) {
            return function (scope, element, attrs) {
                transcludeFn(scope, function(clone) {
                    var title= element.find('title');
                    var time = clone.find('.time');
                    var type = clone.find('.type');
                    var text= clone.find('.content');

                    title.append(time);
                    element.append(type);
                    element.append(text)
                });
            };
        }
    };
});

transcludeFn 是一个 function:transcludeFn(scope, function(clone){}) 作用域和嵌入包含的内容,clone 嵌入的内容是被 jquery 封装过的,有了它,我们就可以做任何想要做的 dom操作 了。

在controller里注入$transclude

先上代码:

app.directive('pane', function() {
    return {
        restrict: 'EA',
        template:
            '<div style="border: 1px solid black;">' +
                '<div class="title" style="background-olor: gray">{{title}}</div>' +
            '</div>',
        replace: true,
        transclude: true,
        controller: [
            '$scope', '$element', '$transclude',
            function ($scope, $element, $transclude) {
                $transclude(function(clone, scope) {
                    var title= element.find('title');
                    var time = clone.find('.time');
                    var type = clone.find('.type');
                    var text= clone.find('.content');

                    title.append(time);
                    element.append(type);
                    element.append(text)
                });
            }
        ]
    };
});

换汤不换药,其实就是 $transclude,transcludeFn 这两个函数执行的地方不同。里面是一模一样的。

还有一个需要说明的是transclude的作用域的问题。

在官方文档中提到过 deretive 的作用域是单独的,transclude 也创建了一个单独的作用域,而且与 derectvie 的作用域是平行的,还是拿上面的例子来说。 <div ng-controller="Ctrl">...</div> 首先controller Ctrl会创建一个作用域scope1,derective Pane会在scope1下面创建一个scope2,scope1 包含 scope2,tranclude又会在scope1下面创建一个scope3,scope1也包含scope3,scope2和scope3是兄弟关系,平行的两个子作用域。

好,我们可以来验证一下:

在controller中加日志

function Ctrl($scope) {
    $scope.title = 'Lorem Ipsum';
    $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
    console.log('scope1', $scope);
}

在derective中添加日志

app.directive('pane', function() {
    return {
        restrict: 'EA',
        template:
            '<div style="border: 1px solid black;">' +
                '<div class="title" style="background-olor: gray">{{title}}</div>' +
            '</div>',
        replace: true,
        transclude: true,
        controller: [
            '$scope', '$element', '$transclude',
            function ($scope, $element, $transclude) {
                console.log('scope2', $scope)
                $transclude(function(clone, scope) {
                    console.log('scope3', scope);
                    var title= element.find('title');
                    var time = clone.find('.time');
                    var type = clone.find('.type');
                    var text= clone.find('.content');
                    title.append(time);
                    element.append(type);
                    element.append(text)
                });
            }
        ],
    };
});

在控制台可以看到

scope1 a {$id: "003", this: a, $$listeners: Object, $parent: e, $$childTail: null…}
scope2 e {$id: "004", $$childTail: null, $$childHead: null, $$prevSibling: null, $$nextSibling: null…}
scope3 a {$id: "005", this: a, $$listeners: Object, $parent: a, $$childTail: null…}

点开 scope2 和 scope3,就能看到 $parent 的 Id 为003,这就印证了我们的观点。

Previous在Angular指令中使用NgModelController做数据绑定Next使用Angularjs的ng-cloak指令避免页面乱码

Last updated 5 years ago

Was this helpful?

本文链接:

http://blog.gejiawen.com/2014/07/17/usage-for-angularjs-ng-transclude/