• [其他] NeuroFluid: 流体仿真的人工智能新范式
    近日,上海交通大学人工智能研究院杨小康教授、王韫博助理教授指导的AI+Science研究团队的成果《NeuroFluid: Fluid Dynamics Grounding with Particle-Driven Neural Radiance Fields》被国际顶级机器学习会议ICML 2022收录。论文所提出的“神经流体(NeuroFluid)”模型,利用基于神经隐式场的人工智能可微渲染技术,将流体物理仿真看作求解流体场景三维渲染问题的逆问题——从流体场景的一段多视角表观图像中,即可反推出流体内部的运动规律。这项成果为计算流体动力学、多粒子动力学系统研究开辟了一种人工智能新途径。论文链接: https://www.zhuanzhi.ai/paper/ddad8ebf86c68fae5d98015f1bc671f7代码地址: github.com/syguan96/NeuroFluid项目主页: syguan96.github.io/NeuroFluid/流体运动研究是重要的自然科学基础研究领域,在航空航天、大气、海洋、航运、能源、建筑、环境等众多领域有着广泛应用。在传统研究方法中,求解流体运动(例如速度场)需要首先在理论上精确刻画流体的动力学模型,并结合微分方程、数值分析对模型求解。但是通常对于复杂问题(例如湍流),人们很难用数学物理方程进行描述,复杂流体的Navier-Stokes方程是世界级千禧难题,至今依然没被很好解决。现有基于深度学习的方法通常从拉格朗日视角描述流体,即流体被看作由许多粒子组成,通过测定和约束每个粒子的运动即可测定和改变流体的运动。但是大多数方法通常要求已知流体的物理属性(例如粘性),并且需要粒子的运动信息(位置和速度)作为训练数据,这在真实场景中几乎不太可能。针对流体力学模型难以刻画和求解的问题,本文提出一种名为NeuroFluid的神经网络方法,实现流体动态反演(fluid dynamics grounding),即根据稀疏视角下对流体的2D表观视觉观察,推断推流体内在的3D物理运动状态,例如粒子的速度和位置等。如图2所示,NeuroFluid包含基于神经网络的流体粒子状态转移模型(Particle Transition Model)和由粒子驱动的神经网络渲染器(PhysNeRF),并将二者整合到一个端到端的联合优化框架中。优化过程包含三个阶段:1. 模拟:粒子状态转移模型根据初始状态(可用立体视觉方法粗估)预测流体粒子在后续时刻的运动轨迹;2. 渲染:神经网络渲染器PhysNeRF(图2右)根据粒子的几何信息将模拟结果渲染成图像;3. 比对:渲染图像和真实图像比对,计算误差,通过梯度反向传递优化模型参数。图2. NeuroFluid的训练过程(图左)及PhysNeRF的渲染示意(图右)本文使用的流体数据(HoneyCone、WaterCube、WaterSphere)具有不同的物理属性(如密度、粘度、颜色)或初始状态(如流体粒子位置、整体形态)。下列的实验从粒子动态反演、未来状态预测、新视角图像渲染、PhysNeRF域外场景泛化,验证了NeuroFluid的有效性。1实验1:流体粒子动态反演本实验计算从图像反演的粒子位置与真实粒子位置之间的距离误差(Pred2GT distance),作为评价指标。图3展示了NeuroFluid与流体粒子预测的有监督方法DLF[1]的数值结果对比,显然,NeuroFluid从视频中反演的流体粒子状态比DLF(用粒子运动速度和位置作为训练数据)更准确。图4对模型的粒子状态推断结果做了可视化,注意到随着时间的推移,NeuroFluid相比基线模型,其反演结果运动更加自然,能更好地匹配真实流体动态。图3. NeuroFluid(浅蓝色)在三个测试集上关于流体粒子位置的反演结果,相比流体粒子仿真的有监督模型DLF,NeuroFluid从图像推理流体内部状态,明显具有更好的准确性图4. NeuroFluid(第三行)在WaterCube场景中对流体粒子位置的推断结果,图中第一行为生成对应观测图像序列时所使用的“真实”流体粒子位置2实验2:流体未来状态预测在有效学习了流体的粒子状态转移模型后,可以很方便地实现预测流体在未来时刻的运动状态。如图5所示,本实验评估未来十个时刻内,模型预测的粒子位置与真实情况的误差。结果表明,NeuroFluid能够通过视觉观测学习流体运动的规律,推演合理的流体未来动态。图5. 流体未来状态预测误差。其中,DLF*表示将基线模型在与测试场景物理属性相近的数据上进行微调;DLF+表示将基线模型直接在测试场景上进行微调3实验3:流体场景的新视角图像渲染为了验证PhysNeRF渲染器的有效性,本实验在新视角合成(novel view synthesis)的任务上,广泛对比了各种基于神经隐式场的可微渲染技术,包括NeRF[2],NeRT-T (即NeRF+Time Index), D-NeRF[3]和Li et al. (2022)[4]等。如图6所示,在输入了粒子几何信息的情况下,NeuroFluid的渲染结果不仅在动态上与目标结果的匹配度最高,而且可以更好地渲染出流体的细节(如溅起的水珠)。图6. 新视角合成结果对比,左起第一列为新视角下的目标图像4实验4:  域外场景泛化PhysNeRF的基本假设是流体图像渲染应以粒子状态为驱动,故而应具有不同粒子分布下的强大泛化能力。为验证其泛化能力,本实验在使用有限的场景训练好PhysNeRF渲染器后,在测试时改变了流体的初始形貌,如图7所示,该几何形状为计算机图形学经典的Stanford Bunny。值得注意的是,在没有用Stanford Bunny数据对模型进行训练微调的情况下,PhysNeRF较为精细地渲染出了流体的表面细节。图7. PhysNeRF在域外流体场景(训练所未见)上的泛化效果总结:上海交通大学AI+Science研究团队所提出的NeuroFluid模型能成功拟合符合视觉观测的流体运动转移规律,从视觉表观观测反演流体内在运动,有望为传统流体力学无法准确刻画的复杂流体运动(如湍流)提供一种全新的计算范式。
  • [算子编译] 3D渲染库
    【功能模块】3D渲染库kaolin【操作步骤&问题现象】1、使用mindspore框架做三维重建的过程,需要使用到kaolin.render.mesh.dibr_rasterization()算子2、源码中包括kaolin._C.render.mesh.rasterize_backward_cuda如何实现该算子呢【截图信息】
  • [技术干货] 浏览器渲染机制
    浏览器渲染机制浏览器采用流式布局模型(Flow Based Layout)浏览器会把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了渲染树(Render Tree)。有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。2. 重绘由于节点的几何属性发生改变或者由于样式发生改变而不会影响布局的,称为重绘,例如outline, visibility, color、background-color等,重绘的代价是高昂的,因为浏览器必须验证DOM树上其他节点元素的可见性。3. 回流回流是布局或者几何属性需要改变就称为回流。回流是影响浏览器性能的关键因素,因为其变化涉及到部分页面(或是整个页面)的布局更新。一个元素的回流可能会导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流。<body> <div class="error">     <h4>我的组件</h4>     <p><strong>错误:</strong>错误的描述…</p>     <h5>错误纠正</h5>     <ol>         <li>第一步</li>         <li>第二步</li>     </ol> </div> </body>在上面的HTML片段中,对该段落(标签)回流将会引发强烈的回流,因为它是一个子节点。这也导致了祖先的回流(div.error和body – 视浏览器而定)。此外,和也会有简单的回流,因为其在DOM中在回流元素之后。大部分的回流将导致页面的重新渲染。回流必定会发生重绘,重绘不一定会引发回流。4. 浏览器优化现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。主要包括以下属性或方法:offsetTop、offsetLeft、offsetWidth、offsetHeightscrollTop、scrollLeft、scrollWidth、scrollHeightclientTop、clientLeft、clientWidth、clientHeightwidth、heightgetComputedStyle()getBoundingClientRect()所以,我们应该避免频繁的使用上述的属性,他们都会强制渲染刷新队列。5. 减少重绘与回流CSS使用 transform 替代 top使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局避免使用table布局,可能很小的一个小改动会造成整个 table 的重新布局。尽可能在DOM树的最末端改变class,回流是不可避免的,但可以减少其影响。尽可能在DOM树的最末端改变class,可以限制了回流的范围,使其影响尽可能少的节点。避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。<div>   <a> <span></span> </a> </div> <style>   span {     color: red;   }   div > a > span {     color: red;   } </style>对于第一种设置样式的方式来说,浏览器只需要找到页面中所有的 span 标签然后设置颜色,但是对于第二种设置样式的方式来说,浏览器首先需要找到所有的 span 标签,然后找到 span 标签上的 a 标签,最后再去找到 div 标签,然后给符合这种条件的 span 标签设置颜色,这样的递归过程就很复杂。所以我们应该尽可能的避免写过于具体的 CSS 选择器,然后对于 HTML 来说也尽量少的添加无意义标签,保证层级扁平。将动画效果应用到position属性为absolute或fixed的元素上,避免影响其他元素的布局,这样只是一个重绘,而不是回流,同时,控制动画速度可以选择 requestAnimationFrame,详见探讨 requestAnimationFrame。避免使用CSS表达式,可能会引发回流。将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点,例如will-change、video、iframe等标签,浏览器会自动将该节点变为图层。CSS3 硬件加速(GPU加速),使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 。但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。JavaScript避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
  • [技术干货] 浏览器渲染机制
    浏览器渲染机制浏览器采用流式布局模型(Flow Based Layout)浏览器会把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了渲染树(Render Tree)。有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。2. 重绘由于节点的几何属性发生改变或者由于样式发生改变而不会影响布局的,称为重绘,例如outline, visibility, color、background-color等,重绘的代价是高昂的,因为浏览器必须验证DOM树上其他节点元素的可见性。3. 回流回流是布局或者几何属性需要改变就称为回流。回流是影响浏览器性能的关键因素,因为其变化涉及到部分页面(或是整个页面)的布局更新。一个元素的回流可能会导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流。<body> <div class="error">     <h4>我的组件</h4>     <p><strong>错误:</strong>错误的描述…</p>     <h5>错误纠正</h5>     <ol>         <li>第一步</li>         <li>第二步</li>     </ol> </div> </body>在上面的HTML片段中,对该段落(标签)回流将会引发强烈的回流,因为它是一个子节点。这也导致了祖先的回流(div.error和body – 视浏览器而定)。此外,和也会有简单的回流,因为其在DOM中在回流元素之后。大部分的回流将导致页面的重新渲染。回流必定会发生重绘,重绘不一定会引发回流。4. 浏览器优化现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。主要包括以下属性或方法:offsetTop、offsetLeft、offsetWidth、offsetHeightscrollTop、scrollLeft、scrollWidth、scrollHeightclientTop、clientLeft、clientWidth、clientHeightwidth、heightgetComputedStyle()getBoundingClientRect()所以,我们应该避免频繁的使用上述的属性,他们都会强制渲染刷新队列。5. 减少重绘与回流CSS使用 transform 替代 top使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局避免使用table布局,可能很小的一个小改动会造成整个 table 的重新布局。尽可能在DOM树的最末端改变class,回流是不可避免的,但可以减少其影响。尽可能在DOM树的最末端改变class,可以限制了回流的范围,使其影响尽可能少的节点。避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。<div>   <a> <span></span> </a> </div> <style>   span {     color: red;   }   div > a > span {     color: red;   } </style>对于第一种设置样式的方式来说,浏览器只需要找到页面中所有的 span 标签然后设置颜色,但是对于第二种设置样式的方式来说,浏览器首先需要找到所有的 span 标签,然后找到 span 标签上的 a 标签,最后再去找到 div 标签,然后给符合这种条件的 span 标签设置颜色,这样的递归过程就很复杂。所以我们应该尽可能的避免写过于具体的 CSS 选择器,然后对于 HTML 来说也尽量少的添加无意义标签,保证层级扁平。将动画效果应用到position属性为absolute或fixed的元素上,避免影响其他元素的布局,这样只是一个重绘,而不是回流,同时,控制动画速度可以选择 requestAnimationFrame,详见探讨 requestAnimationFrame。避免使用CSS表达式,可能会引发回流。将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点,例如will-change、video、iframe等标签,浏览器会自动将该节点变为图层。CSS3 硬件加速(GPU加速),使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 。但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。JavaScript避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
  • [技术干货] 助你上手Vue3全家桶之Vue3教程[转载]
    前言这些内容是博主在学习过程中记录下来的,有一些不重要的点就跳过了,需要时自行查询文档。其实V2到V3的学习成本不高,熟悉V2的话,看完这篇文章就可以上手V3。Vue3官网在线源码编译地址1,setupsetup是所有Composition API的容器,值为一个函数。组件中所用到的数据、方法等等,均要配置在setup中,它会在beforeCreate之前执行一次,注意:V3里this不再是指向Vue实例,访问this会是undefined1.1,返回值若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。若返回一个渲染函数:则可以自定义渲染内容。1.2,注意点尽量不要与V2配置混用V2配置(data、methos、computed…)中可以访问到setup中的属性、方法。但在setup中不能访问到V2配置(data、methods、computed…)。如果有重名, setup优先。setup不能是一个async函数因为返回值不再return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)1.3,语法<script>import { ref, reactive } from 'vue'export default {    name: 'Home',    setup(props, context) {        const title = ref('标题')        const data = reactive({            value: '哈哈哈'        })        return {          title,          data        }    }}</script>1.4,setup的参数props:值为对象,包含组件外部传递过来,且组件内部声明接收了的属性context:上下文对象attrs: 值为对象,包含组件外部传递过来,但没有在props配置中声明的属性, 相当于this.$attrsslots: 收到的插槽内容, 相当于this.$slotsemit: 分发自定义事件的函数, 相当于this.$emit2,ref 创建响应式数据使用ref可以创建一个包含响应式数据的引用对象(reference对象,简称ref对象),可以是基本类型、也可以是对象。语法// 创建const xxx = ref(value)// 使用xxx.value// 在模板中<div>{{xxx}}</div>3,reactive 创建响应式数据定义一个对象类型的响应式数据,内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作语法// 创建const xxx = reactive({    xxx: ''})// 使用xxx.xxx4,computed 计算属性与V2中computed配置功能一致语法import { computed } from 'vue'setup(){    // 简写语法    let fullName = computed(() => {        return person.firstName + '-' + person.lastName    })        // 完整语法    let fullName = computed({        get(){            return person.firstName + '-' + person.lastName        },        set(value){            const nameArr = value.split('-')            person.firstName = nameArr[0]            person.lastName = nameArr[1]        }    })        return fullName5,watch 监听与V2中watch配置功能一致,语法有点改动语法情况一:监视ref定义的响应式数据watch(sum, (newValue, oldValue) => {    console.log('sum变化了', newValue, oldValue)}, {immediate:true})情况二:监视多个ref定义的响应式数据watch([sum, msg], (newValue,oldValue) => {    console.log('sum或msg变化了', newValue,oldValue)}) 情况三:监视reactive定义的响应式数据// 若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue// 若watch监视的是reactive定义的响应式数据,则强制开启了深度监视watch(person, (newValue, oldValue) => {    console.log('person变化了', newValue, oldValue)}, { immediate:true, deep:false }) // 此处的deep配置不再奏效情况四:监视reactive定义的响应式数据中的某个属性watch(() => person.job, (newValue, oldValue) => {    console.log('person的job变化了', newValue, oldValue)}, { immediate:true, deep:true }) 情况五:监视reactive定义的响应式数据中的某些属性watch([() => person.job, () => person.name], (newValue, oldValue) => {    console.log('person的job变化了', newValue, oldValue)}, { immediate:true, deep:true })特殊情况:此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效watch(() => person.job, (newValue, oldValue) => {    console.log('person的job变化了', newValue, oldValue)}, { deep:true })6,watchEffect 监听回调和watch的区别是,watch既要指明监视的属性,也要指明监视的回调。而watchEffect,不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性,不用写返回值。语法// 回调中用到的数据只要发生变化,则直接重新执行回调watchEffect(() => {    const x1 = sum.value    const x2 = person.age    console.log('watchEffect配置的回调执行了')})7,生命周期生命周期全都写在setup中7.1,改变beforeDestroy 改名为 beforeUnmountdestroyed 改名为 unmountedbeforeCreate => setupcreated => setupbeforeMount => onBeforeMountmounted => onMountedbeforeUpdate => onBeforeUpdateupdated => onUpdatedbeforeUnmount => onBeforeUnmountunmounted => onUnmounted7.2,语法setup() {    onMounted(() => {      console.log('mounted')    })}8,toRef 创建ref创建一个ref对象,其value值指向另一个对象中的某个属性语法const state = reactive({  foo: 1,  bar: 2})const fooRef = toRef(state, 'foo')// 传递propsexport default {  setup(props) {    useSomeFeature(toRef(props, 'foo'))  }}9,toRefs 响应式转换将响应式对象转换为普通对象,其中结果对象的每个property都是指向原始对象相应property的ref语法const state = reactive({  foo: 1,  bar: 2})const stateAsRefs = toRefs(state)// 此时state和stateAsRefs是关联的10,shallowReactive 响应式外层转换只处理对象最外层属性的响应式(浅响应式)。适用于:一个对象数据,结构比较深, 但变化时只是外层属性变化语法const state = shallowReactive({  foo: 1,  nested: {    bar: 2  }})11,shallowRef 基本数据响应式只处理基本数据类型的响应式, 不进行对象的响应式处理。适用于:一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换语法const shallow = shallowRef({  greet: 'Hello, world'})12,readonly 响应式变只读让一个响应式数据变为只读的(深只读),应用于不希望数据被修改时语法const shallow = shallowRef({  greet: 'Hello, world', // 只读  nested: {    bar: 2 // 只读  }})13,shallowReadonly 响应式变只读让一个响应式数据变为只读的(浅只读),应用于不希望数据被修改时语法const shallow = shallowReadonly({  foo: 1, // 只读  nested: {    bar: 2 // 非只读  }})14,toRaw 响应式变非响应式将一个由reactive生成的响应式对象转为普通对象,对这个普通对象的所有操作,不会引起页面更新。语法const foo = {}const Foo = reactive(foo)console.log(toRaw(Foo) === foo) // true15,markRaw 标记永远不响应式标记一个对象,使其永远不会再成为响应式对象,有些值不应被设置为响应式的,例如复杂的第三方类库等,当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。语法const foo = markRaw({})console.log(isReactive(reactive(foo))) // false// 嵌套在其他响应式对象中时也可以使用const bar = reactive({ foo })console.log(isReactive(bar.foo)) // false16,customRef 依赖更新控制创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收track和trigger函数作为参数,并且应该返回一个带有get和set的对象。语法<script>import { customRef } from 'vue'export default {    name: 'Home',    setup() {        // 实现防抖函数        const fn = function(value, delay = 500) {            let timeout            return customRef((track, trigger) => {                return {                    get() {                        track()                        return value                    },                    set(newValue) {                        clearInterval(timeout)                        timeout = setTimeout(() => {                            console.log(newValue)                            value = newValue                            trigger()                        }, delay)                    }                }            })        }        const keyword = fn('', 500)        return {            keyword        }    }}</script>17,provide & inject 通信实现祖与后代组件间通信,父组件有一个provide选项来提供数据,后代组件有一个inject选项来开始使用这些数据语法// 祖组件setup(){    let car = reactive({ name:'奔驰', price:'40万' })    provide('car', car)}// 后代组件setup(props, context){    const car = inject('car')    return { car }}18,响应式数据的判断18.1,isRef检查一个值是否为一个ref对象语法const val = ref('xxx')isRef(val) // true18.2,isReactive检查一个值是否为一个isReactive对象语法const val = isReactive({})isRef(val) // true18.3,isReadonly检查一个对象是否是由readonly创建的只读代理语法const state = reactive({  name: 'John'})console.log(isReactive(state)) // true18.4,isProxy检查对象是否是由reactive或readonly创建的proxy语法const state = reactive({  name: 'John'})console.log(isProxy(state)) // true19,teleport 移动dom组件Teleport提供了一种干净的方法,允许我们控制在DOM中哪个父节点下渲染了HTML,而不必求助于全局状态或将其拆分为两个组件。语法<teleport to="移动位置">    <div v-if="isShow" class="mask">        <div class="dialog">            <h3>我是一个弹窗</h3>            <button @click="isShow = false">关闭弹窗</button>        </div>    </div></teleport>// to的格式<teleport to="#some-id" /><teleport to=".some-class" /><teleport to="[data-teleport]" />// disabled的格式<teleport to="#popup" :disabled="displayVideoInline">  <video src="./my-movie.mp4"></teleport>20,Suspense 异步渲染组件等待异步组件时先渲染一些额外内容,让应用有更好的用户体验语法<template>    <div class="app">        <h3>我是App组件</h3>        <Suspense>            <template #default>                <Child/>            </template>            <template #fallback>                <h3>加载中.....</h3>            </template>        </Suspense>    </div></template>import { defineAsyncComponent } from 'vue'const Child = defineAsyncComponent(() => import('./components/Child.vue'))components: {    Child}21,全局API调整将全局的API,即:Vue.xxx调整到应用实例(app)上V2的api    V3的apiVue.config.xxxx    app.config.xxxxVue.component    app.componentVue.directive    app.directiveVue.mixin    app.mixinVue.use    app.useVue.prototype    app.config.globalProperties22,移除api名称    现状Vue.config.productionTip    已移除config.keyCodes    已移除$children    已移除$listeners    已移除$on    已移除$off    已移除$once    已移除filters    已移除.native    已移除23,Ref 获取DOM由于V3中不在存在this,所以ref的获取调整了23.1,单个ref语法<div ref="Qrcode" class="qr_codeode_url" />import { ref } from 'vue'export default {  setup() {    const Qrcode = ref(null)    // 挂载后    onMounted(() => {        console.log(Qrcode.value)    })    return {      Qrcode    }  }}23.2,循环中的refV3中在for循环元素上绑定ref将不再自动创建$ref数组。要从单个绑定获取多个ref,请将ref绑定到一个更灵活的函数上语法<div v-for="item in list" :ref="setItemRef"></div>import { onBeforeUpdate, onUpdated } from 'vue'export default {  setup() {    let itemRefs = []    const setItemRef = el => {      if (el) {        itemRefs.push(el)      }    }    onBeforeUpdate(() => {      itemRefs = []    })    onUpdated(() => {      console.log(itemRefs)    })    return {      setItemRef    }  }}itemRefs不必是数组:它也可以是一个对象,其ref可以通过迭代的key被设置如有需要,itemRef也可以是响应式的,且可以被侦听24,emits 自定义事件定义一个组件可以向其父组件触发的事件// 在子组件中<h1 @click="father">{{ msg }}</h1>export default {    name: 'HelloWorld',    props: {        msg: {            type: String,            default: ''        }    },    emits: ['close'],    setup(props, { emit }) {        const father = function() {            emit('close', 'child')        }        return {            father        }    }}// 在父组件中<HelloWorld :msg="msg" @click="fn" @close="fn2" />25,$nextTick 异步更新使用方式修改import { nextTick } from 'vue'nextTick(() => {  // ...})26,hook 生命周期事件通过事件来监听组件生命周期中的关键阶段语法// V2的语法<template>  <child-component @hook:updated="onUpdated"></template>// V3的语法<template>  <child-component @vnode-updated="onUpdated"></template>// 驼峰写法<template>  <child-component @vnodeUpdated="onUpdated"></template————————————————版权声明:本文为CSDN博主「鹏多多i」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/pdd11997110103/article/details/121035412
  • [技术干货] 浏览器渲染机制
    浏览器渲染机制浏览器采用流式布局模型(Flow Based Layout)浏览器会把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了渲染树(Render Tree)。有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。2. 重绘由于节点的几何属性发生改变或者由于样式发生改变而不会影响布局的,称为重绘,例如outline, visibility, color、background-color等,重绘的代价是高昂的,因为浏览器必须验证DOM树上其他节点元素的可见性。3. 回流回流是布局或者几何属性需要改变就称为回流。回流是影响浏览器性能的关键因素,因为其变化涉及到部分页面(或是整个页面)的布局更新。一个元素的回流可能会导致了其所有子元素以及DOM中紧随其后的节点、祖先节点元素的随后的回流。<body> <div class="error">     <h4>我的组件</h4>     <p><strong>错误:</strong>错误的描述…</p>     <h5>错误纠正</h5>     <ol>         <li>第一步</li>         <li>第二步</li>     </ol> </div> </body>在上面的HTML片段中,对该段落(标签)回流将会引发强烈的回流,因为它是一个子节点。这也导致了祖先的回流(div.error和body – 视浏览器而定)。此外,和也会有简单的回流,因为其在DOM中在回流元素之后。大部分的回流将导致页面的重新渲染。回流必定会发生重绘,重绘不一定会引发回流。4. 浏览器优化现代浏览器大多都是通过队列机制来批量更新布局,浏览器会把修改操作放在队列中,至少一个浏览器刷新(即16.6ms)才会清空队列,但当你获取布局信息的时候,队列中可能有会影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流与重绘来确保返回正确的值。主要包括以下属性或方法:offsetTop、offsetLeft、offsetWidth、offsetHeightscrollTop、scrollLeft、scrollWidth、scrollHeightclientTop、clientLeft、clientWidth、clientHeightwidth、heightgetComputedStyle()getBoundingClientRect()所以,我们应该避免频繁的使用上述的属性,他们都会强制渲染刷新队列。5. 减少重绘与回流CSS使用 transform 替代 top使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局避免使用table布局,可能很小的一个小改动会造成整个 table 的重新布局。尽可能在DOM树的最末端改变class,回流是不可避免的,但可以减少其影响。尽可能在DOM树的最末端改变class,可以限制了回流的范围,使其影响尽可能少的节点。避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。<div>   <a> <span></span> </a> </div> <style>   span {     color: red;   }   div > a > span {     color: red;   } </style>对于第一种设置样式的方式来说,浏览器只需要找到页面中所有的 span 标签然后设置颜色,但是对于第二种设置样式的方式来说,浏览器首先需要找到所有的 span 标签,然后找到 span 标签上的 a 标签,最后再去找到 div 标签,然后给符合这种条件的 span 标签设置颜色,这样的递归过程就很复杂。所以我们应该尽可能的避免写过于具体的 CSS 选择器,然后对于 HTML 来说也尽量少的添加无意义标签,保证层级扁平。将动画效果应用到position属性为absolute或fixed的元素上,避免影响其他元素的布局,这样只是一个重绘,而不是回流,同时,控制动画速度可以选择 requestAnimationFrame,详见探讨 requestAnimationFrame。避免使用CSS表达式,可能会引发回流。将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点,例如will-change、video、iframe等标签,浏览器会自动将该节点变为图层。CSS3 硬件加速(GPU加速),使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘 。但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。JavaScript避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
  • [技术干货] OpenHarmony 3.1 Release版本关键特性解析——新的图形框架可以带来什么
    3 月 31 日,OpenAtom OpenHarmony(以下简称“OpenHarmony”) 3.1 Release 版本正式发布了。此版本为大家带来了全新的图形框架,实现了UI框架显示、多窗口、流畅动画等基础能力,夯实了 OpenHarmony 系统能力基座,下面就带大家详细了解新图形框架。 一、完整能力视图新图形框架的能力在持续构建中,图1展示了新图形框架当前及未来提供的完整能力视图。图1 OpenHarmony图形完整能力视图按照分层抽象和模块化的架构设计原则,新图形框架分为接口层、框架层和引擎层。各层级说明如下:● 接口层:提供图形 NDK(native development kit,原生开发包)能力,包括 OpenGL ES、Native Drawing 等绘制接口能力。● 框架层:由 Render Service、Animation、Effect、Drawing、显示与内存管理等核心模块组成。框架层各模块说明如下:● 引擎层:包括 2D 图形库和 3D 图形引擎两个模块。2D 图形库提供 2D 图形绘制底层 API,支持图形绘制与文本绘制底层能力。3D 图形引擎能力尚在构建中。二、新图形框架的亮点经过上一节介绍,我们对新图形框架的完整能力有了基本的了解。那么,新图形框架有什么亮点呢?新图形框架在渲染、动画流畅性、接口方面重点发力:(1)渲染方面通常来讲,UI 界面显示分为两个部分:一是描述的UI元素在应用内部显示,二是多个应用的界面在屏幕上同时显示。对此,新图形框架从功能上做了相应的设计:控件级渲染和窗口级渲染。“控件级渲染”重点考虑如何跟UI框架前端进行对接,需要将ArkUI框架的控件描述转换成绘制指令,并提供对应的节点管理以及渲染能力。而“窗口级渲染”重点考虑如何将多个应用合成显示到同一个屏幕上。(2)动画流畅性方面我们深挖动画处理流程中的各个环节,对新图形框架进行了新的动画实现设计,提升动画的流畅性体验。(3)接口方面新图形框架在接口层提供了更丰富的接口能力。下面为大家一一详细介绍新图形框架的亮点特性。1. 控件级渲染新图形框架实现了基于 RenderService(简称 RS)的控件级渲染功能,如图 2 所示。图2 控件级渲染控件级渲染功能具有以下特点:● 支持 GPU 渲染,提升渲染性能。● 动画逻辑从主线程中剥离,提供独立的步进驱动机制。● 将渲染节点属性化,属性与内容分离。2. 窗口级渲染新图形框架实现了基于 RenderService 的窗口级渲染功能,如图 3 所示。图3 窗口级渲染窗口级渲染功能具有以下特点:● 取代 Weston 合成框架,实现RS新合成框架。● 支持硬件 VSync/软件 Vsync。● 支持基于 NativeWindow 接入 EGL/GLES 的能力。● 更灵活的合成方式,支持硬件在线合成/CPU 合成/混合合成(GPU 合成即将上线)。● 支持多媒体图层在线 overlay。3. 更流畅的动画体验动画流畅性是一项很基本、也很关键的特性,直接影响用户体验。为了提升动画的流畅性体验,我们深挖动画处理流程中的各个环节,对新图形框架进行了新的动画实现设计。如图 4 所示,传统动画的实现流程如下:(1) 应用创建动画,设置动画参数;(2) 每帧回调,修改控件参数,重新测量、布局、绘制;(3) 内容渲染。图4 传统动画实现经过深入分析,我们发现传统动画实现存在以下缺点:(1)UI 与动画一起执行,UI 的业务阻塞会影响动画的执行,导致动画卡顿。(2)每帧回调修改控件属性,会触发测量布局录制,导致耗时增加。针对以上两点缺陷,我们对新图形框架进行了新的动画实现设计,如图5所示。图5 新框架的动画实现(1)动画与 UI 分离。动画在渲染线程步进,与 UI 业务线程分离。(2)动画仅测量、布局、绘制一次,降低动画负载。通过计算最终界面属性值,对有改变的控件添加动画,动画过程中不测量、布局、绘制,提升性能。4. 对外提供的接口新图形框架提供了丰富的接口:(1)SDK:支持 WebGL 1.0、WebGL 2.0,满足 JS 开发者的 3D 开发的需求。WebGL 开发指导https://docs.openharmony.cn/pages/v3.1/zh-cn/OpenHarmony-Overview_zh.md/(2)NDK:支持 OpenGL ES3.X,可以通过 XComponent 提供的 nativewindow 创建 EGL/OPENGL 绘制环境,满足游戏引擎等开发者对 3D 绘图能力的需求。图6 OpenGL ES使用示例新图形框架还处于不断完善过程中,我们将基于新框架提供更多的能力,相信以后会给大家带来更多的惊喜,敬请期待~转载于OpenAtom OpenHarmony微信公众号
  • [其他问题] MindSpore现在或者未来能提供类似pytorch3d的可谓渲染框架么
    我现在想把一些用pytorch3d写的可微渲染部分的代码转换为mindspore,但我查了一下文档,好像没有看到相关的内容。有没有什么可行的方法可以让我把pytorch3d的代码重写为mindspore框架下呢?
  • [问题求助] 【robox】【渲染功能】robox跑起来后跑安兔兔是软件渲染,怎么设置成用GPU渲染?
    【功能模块】渲染功能【操作步骤&问题现象】1、按照robox步骤,在鲲鹏920服务器上面启动robox,2、然后跑安兔兔进行行性能测评,发现GPU测试没有数据,查看测评报告是LLVM渲染3、如何设置才能通过GPU渲染?【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [问题求助] 【robox】【mesa】robox跑起来后,怎么知道是通过wx5100渲染,还是软件渲染?
    【功能模块】robox渲染模块【操作步骤&问题现象】1、根据文档指引,robox可以跑起来,远程通过scrcpy 也能显示操作。2.robox跑起来后,怎么知道是通过wx5100渲染,还是软件渲染?3.如果要适配新的显卡,要从哪里入手?【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [问题求助] 【kunpeng920服务器】【AMDGPU功能】android通过mesa调用AMD wx5100渲染出现异常
    【功能模块】kunpeng920服务器通过AMDGPU渲染【操作步骤&问题现象】1、在鲲鹏920,上带AMD wx5100 GPU,android asop 调用 mesa-22.0.0 and mesa-21.1.6进行渲染。都出现异常。2、【截图信息】【日志信息】(可选,上传日志内容或者附件)03-18 11:55:52.415 14435 14435 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 03-18 11:55:52.415 14435 14435 F DEBUG : Build fingerprint: 'redroid/redroid_arm64_only/redroid_arm64_only:12/SQ1D.220205.004/eng.frank.20220305.064003:userdebug/test-keys' 03-18 11:55:52.415 14435 14435 F DEBUG : Revision: '0' 03-18 11:55:52.415 14435 14435 F DEBUG : ABI: 'arm64' 03-18 11:55:52.415 14435 14435 F DEBUG : Timestamp: 2022-03-18 11:55:52.156479216+0000 03-18 11:55:52.415 14435 14435 F DEBUG : Process uptime: 0s 03-18 11:55:52.415 14435 14435 F DEBUG : Cmdline: com.android.systemui 03-18 11:55:52.415 14435 14435 F DEBUG : pid: 14118, tid: 14429, name: GrallocUploadTh >>> com.android.systemui <<< 03-18 11:55:52.415 14435 14435 F DEBUG : uid: 10062 03-18 11:55:52.415 14435 14435 F DEBUG : signal 7 (SIGBUS), code 2 (BUS_ADRERR), fault addr 0xefc1a6277000 03-18 11:55:52.415 14435 14435 F DEBUG : x0 0000efc1a6277000 x1 b400efc0af1ec250 x2 00000000000000e8 x3 0000efc1a6277000 03-18 11:55:52.415 14435 14435 F DEBUG : x4 b400efc0af1ec338 x5 0000efc1a62770e8 x6 0000000000000000 x7 0000000000000000 03-18 11:55:52.415 14435 14435 F DEBUG : x8 0000000000000001 x9 0000000000000000 x10 0000000000000004 x11 000000000000003e 03-18 11:55:52.415 14435 14435 F DEBUG : x12 0000000000000000 x13 0000000000000000 x14 b400efc0af1ec250 x15 0000000000000000 03-18 11:55:52.415 14435 14435 F DEBUG : x16 0000efbe6c198580 x17 0000efc190dd9c20 x18 0000efbe1d5d0000 x19 0000000000000100 03-18 11:55:52.415 14435 14435 F DEBUG : x20 0000efc1a6277000 x21 b400efc0af1ec250 x22 00000000000000e8 x23 000000000000003e 03-18 11:55:52.415 14435 14435 F DEBUG : x24 0000000000000001 x25 00000000000000e8 x26 00000000000000e8 x27 0000efc1a6277000 03-18 11:55:52.415 14435 14435 F DEBUG : x28 000000000000003a x29 0000efbe1e343420 03-18 11:55:52.415 14435 14435 F DEBUG : lr 0000efbe6b77d200 sp 0000efbe1e343410 pc 0000efc190dd9ba8 pst 0000000020000000 03-18 11:55:52.415 14435 14435 F DEBUG : backtrace: 03-18 11:55:52.415 14435 14435 F DEBUG : #00 pc 000000000004bba8 /apex/com.android.runtime/lib64/bionic/libc.so (__memcpy+248) (BuildId: ba489d4985c0cf173209da67405662f9) 03-18 11:55:52.415 14435 14435 F DEBUG : #01 pc 00000000004c51fc /vendor/lib64/dri/libgallium_dri.so (BuildId: 836ba0e12074242913f46921674e5afb) 03-18 11:55:52.415 14435 14435 F DEBUG : #02 pc 00000000009d7dc4 /vendor/lib64/dri/libgallium_dri.so (BuildId: 836ba0e12074242913f46921674e5afb) 03-18 11:55:52.415 14435 14435 F DEBUG : #03 pc 0000000000a8bfc8 /vendor/lib64/dri/libgallium_dri.so (BuildId: 836ba0e12074242913f46921674e5afb) 03-18 11:55:52.415 14435 14435 F DEBUG : #04 pc 0000000000716e94 /vendor/lib64/dri/libgallium_dri.so (BuildId: 836ba0e12074242913f46921674e5afb) 03-18 11:55:52.415 14435 14435 F DEBUG : #05 pc 0000000000698a9c /vendor/lib64/dri/libgallium_dri.so (BuildId: 836ba0e12074242913f46921674e5afb) 03-18 11:55:52.415 14435 14435 F DEBUG : #06 pc 0000000000697f80 /vendor/lib64/dri/libgallium_dri.so (BuildId: 836ba0e12074242913f46921674e5afb) 03-18 11:55:52.415 14435 14435 F DEBUG : #07 pc 0000000000698138 /vendor/lib64/dri/libgallium_dri.so (BuildId: 836ba0e12074242913f46921674e5afb) 03-18 11:55:52.415 14435 14435 F DEBUG : #08 pc 0000000000505238 /system/lib64/libhwui.so (std::__1::__packaged_task_func<android::uirenderer::EGLUploader::onUploadHardwareBitmap(SkBitmap const&, android::uirenderer::FormatInfo const&, AHardwareBuffer*)::'lambda'(), std::__1::allocator<android::uirenderer::EGLUploader::onUploadHardwareBitmap(SkBitmap const&, android::uirenderer::FormatInfo const&, AHardwareBuffer*)::'lambda'()>, void* ()>::operator()()+120) (BuildId: 3d3592fb15b099f3bc3663e5c01ad8af) 03-18 11:55:52.415 14435 14435 F DEBUG : #09 pc 000000000020ef68 /system/lib64/libhwui.so (std::__1::__function::__func<decltype(fp()) android::uirenderer::WorkQueue::runSync<android::uirenderer::EGLUploader::onUploadHardwareBitmap(SkBitmap const&, android::uirenderer::FormatInfo const&, AHardwareBuffer*)::'lambda'()>(android::uirenderer::EGLUploader::onUploadHardwareBitmap(SkBitmap const&, android::uirenderer::FormatInfo const&, AHardwareBuffer*)::'lambda'()&&)::'lambda'(), std::__1::allocator<decltype(fp()) android::uirenderer::WorkQueue::runSync<android::uirenderer::EGLUploader::onUploadHardwareBitmap(SkBitmap const&, android::uirenderer::FormatInfo const&, AHardwareBuffer*)::'lambda'()>(android::uirenderer::EGLUploader::onUploadHardwareBitmap(SkBitmap const&, android::uirenderer::FormatInfo const&, AHardwareBuffer*)::'lambda'()&&)::'lambda'()>, void ()>::operator()()+88) (BuildId: 3d3592fb15b099f3bc3663e5c01ad8af) 03-18 11:55:52.415 14435 14435 F DEBUG : #10 pc 00000000003c62c8 /system/lib64/libhwui.so (android::uirenderer::WorkQueue::process()+156) (BuildId: 3d3592fb15b099f3bc3663e5c01ad8af) 03-18 11:55:52.415 14435 14435 F DEBUG : #11 pc 00000000004ebc7c /system/lib64/libhwui.so (android::uirenderer::ThreadBase::threadLoop()+72) (BuildId: 3d3592fb15b099f3bc3663e5c01ad8af) 03-18 11:55:52.415 14435 14435 F DEBUG : #12 pc 00000000000120ac /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+260) (BuildId: d5dfcc2a0782d6e050d6cf3448f6af45) 03-18 11:55:52.415 14435 14435 F DEBUG : #13 pc 0000000000011964 /system/lib64/libutils.so (thread_data_t::trampoline(thread_data_t const*)+404) (BuildId: d5dfcc2a0782d6e050d6cf3448f6af45) 03-18 11:55:52.415 14435 14435 F DEBUG : #14 pc 00000000000b1910 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+264) (BuildId: ba489d4985c0cf173209da67405662f9) 03-18 11:55:52.415 14435 14435 F DEBUG : #15 pc 00000000000513f0 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: ba489d4985c0cf173209da67405662f9)
  • [ARM原生] 【转】Cuttlefish:GPU 图形加速
    Cuttlefish 的加速图形模式会使用主机的物理图形处理器 (GPU) 进行渲染,具体方法是将客户机渲染命令传递给主机,在主机上运行渲染命令调用,然后将渲染后的结果传递回客户机。默认情况下,Cuttlefish 设备中的客户机端渲染(例如界面和视频播放)由 SwiftShader 处理。SwiftShader 是对 OpenGL API 和 Vulkan API 的软件实现。由于 SwiftShader 是一种软件实现,因此它为 Cuttlefish 提供了一种可在任何主机上运行的通用渲染解决方案。不过,使用 SwiftShader 的性能不及使用正常设备。渲染是一种可大规模并行处理的并行问题,因为像素值是可以单独计算的。图形处理器 (GPU) 是通过加速渲染解决此问题的硬件单元。要求加速图形模式要求主机具有以下驱动程序:支持 EGL 的驱动程序(支持 GL_KHR_surfaceless_context 扩展程序)支持 OpenGL ES 的驱动程序支持 Vulkan 的驱动程序使用加速图形模式GfxStream若要使用 GfxStream 加速图形模式,请使用 --gpu_mode=gfxstream 标记启动本地 Cuttlefish 设备。使用此模式时,OpenGL 和 Vulkan API 调用会直接转到主机。$launch_cvd --gpu_mode=gfxstreamVirgl若要使用 Virgl 加速图形模式,请使用 --gpu_mode=drm_virgl 标记启动本地 Cuttlefish 设备。$launch_cvd --gpu_mode=drm_virgl使用 Virgl 加速图形模式时,OpenGL API 调用会转换为中间表示形式(请参阅 Gallium3D)。系统会将相应中间表示形式传递给主机,并且主机上的 virglrenderer 库会将此中间表示形式重新转换为 OpenGL API 调用。注意:此模式不支持 Vulkan。 声明:        本文转自:https://source.android.google.cn/setup/create/cuttlefish-ref-gpu,仅供学习与交流,非商业用途,版权归原作者所有,如有侵权,请联系删除。
  • [问题求助] 标准页面 表格已经绑定对象模型了 怎么能只渲染出某几个符合条件的数据
    【功能模块】【操作步骤&问题现象】1、2、【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [交流讨论] 【转载】Jinja2 语法简介
    一.Jinja2语法基本语法看过之前模板的例子就知道,Jinja2构成的模板文件中,文本内容大致可以分三种。1  变量取值或者宏调用 {{ }}2  控制结构 {% %}3  注释 {# #}  1      jinja2变量jinja2模板中使用 {{ }} 语法表示一个变量,它是一种特殊的占位符。当利用jinja2进行渲染的时候,它会把这些特殊的占位符进行填充/替换,jinja2支持python中所有的Python数据类型比如列表、字段、对象等。2      jinja2结构控制if语句jinja2中的if语句类似与Python的if语句,它也具有单分支,多分支等多种结构,不同的是,条件语句不需要使用冒号结尾,而结束控制语句,需要使用endif关键字For循环jinja2中的for循环用于迭代Python的数据类型,包括列表,元组和字典。在jinja2中不存在while循环 在for循环中,jinja2还提供了一些特殊的变量,用以来获取当前的遍历状态:变量描述loop.index当前迭代的索引(从1开始)loop.index0当前迭代的索引(从0开始)loop.first是否是第一次迭代,返回boolloop.last是否是最后一次迭代,返回boolloop.length序列中的项目数量loop.revindex到循环结束的次数(从1开始)loop.revindex0到循环结束的次数(从0开始)3      jinja2注释{{# 这是注释 #}}4  Set语句模板中变量的值似乎只有一个来源,就是来自于后端的提供。但是实际上我们可以在模板这个层面对变量进行赋值,就是通过了{% set variable_name="value" %}的形式。这赋予了模板在内部进行变量赋值的能力,提高了灵活性。也可以set一个变量的值为某个函数的返回值二.jinja2中的过滤器  变量可以通过“过滤器”进行修改,过滤器可以理解为是jinja2里面的内置函数和字符串处理函数。  常用的过滤器有:过滤器名称    说明    safe 渲染时值不转义capitialize 把值的首字母转换成大写,其他子母转换为小写 lower 把值转换成小写形式  upper 把值转换成大写形式  title 把值中每个单词的首字母都转换成大写 trim 把值的首尾空格去掉 striptags 渲染之前把值中所有的HTML标签都删掉join  拼接多个值为字符串 replace 替换字符串的值 round 默认对数字进行四舍五入,也可以用参数进行控制int  把值转换成整型   那么如何使用这些过滤器呢? 只需要在变量后面使用管道(|)分割,多个过滤器可以链式调用,前一个过滤器的输出会作为后一个过滤器的输入。   三.jinja2的宏  宏类似于Python中的函数,我们在宏中定义行为,还可以进行传递参数,就像Python中的函数  在宏中定义一个宏的关键字是macro,后面跟其 宏的名称和参数等四.jinja2的继承和Super函数jinja2中最强大的部分就是模板继承。模板继承允许我们创建一个基本(骨架)文件,其他文件从该骨架文件继承,然后针对自己需要的地方进行修改。jinja2的骨架文件中,利用block关键字表示其包涵的内容可以进行修改。以下面的骨架文件base.html为例:  这里定义了四处 block,即:head,title,content,footer。如何继承修改注意看下面的文件   其他没修改的地方则继承PS: super()函数 表示获取block块中原来定义的内容。
  • [技术干货] 2.0数据表格如何实现列样式随内容变化
    方法一:通过js实现,其中“datagrid”为数据表格标识,“result”为列的数据索引:修改后的结果展示:方法二:通过列属性中渲染参数和渲染函数配置,可以通过值的区间不同配置不同的字体颜色背景等,这个方法局限于列数据的值为数字的情况:修改后的结果展示:
总条数:44 到第
上滑加载中