手撸一个 MVVM 不是梦

在实现 VUE 中 MVVM 的系列文章的最后一篇文章中说道:我觉得可响应的数据结构作用很大,在整理了一段时间后,这是我们的最终产出:RD - Reactive Data

ok 回到整理,这篇文章我们不研究 Vue 了,而是根据我们现在的研究成果来手撸一个 MVVM

简单介绍 RD

先看看下我们的研究成果:一个例子

let demo = new RD({
    data(){
        return {
            text: 'Hello',
            firstName: 'aco',
            lastName: 'yang'
        }
    },
    watch:{
        'text'(newValue, oldValue){
            console.log(newValue)
            console.log(oldValue)
        }
    },
    computed:{
        fullName(){
            return this.firstName + ' ' + this.lastName
        }
    },
    method:{
        testMethod(){
            console.log('test')
        }
    }
})

demo.text = 'Hello World'
// console: Hello World
// console: Hello
demo.fullName
// console: aco yang
demo.testMethod()
// console: test

写法上与 Vue 的一样,先说说拥有那些属性吧:

关于数据

  • data
  • computed
  • method
  • watch
  • prop
  • inject/provied

关于生命周期

  • beforeCreate
  • created
  • beforeDestroy
  • destroyed

关于实例间关系

  • parent

实例下的方法:

关于事件

  • $on
  • $once
  • $emit
  • $off

其他方法

  • $watch
  • $initProp

类下方法:

  • use
  • mixin
  • extend

以上便是所有的内容,因为 RD 仅仅关注于数据的变化,所以生命周期就就只有创建和销毁。

对比与 Vue 多了一个 $initProp ,同样的由于仅仅关注于数据变化,所以当父实例相关的 prop 发生变化时,需要手动通知子组件修改相关数据。

其他的属性以及方法的使用与 Vue 一致。

ok 大概说了下,具体的内容可以点击查看

手撸 MVVM

有了 RD 我们来手撸一个 MVVM 框架。

我们先确定我们大致需要什么?

  1. 一个模板引擎(不然怎么把数据变成 dom 结构)
  2. 现在主流都用虚拟节点来实现,我们也加上

ok 模板引擎,JSX 语法不错,来一份。

接着虚拟节点,github 上搜一搜,ok 找到了,点击查看

所有条件都具备了,我们的实现思路如下:

RD + JSX + VNode = MVVM

具体的实现我们一边写 TodoList 一边实现

首先我们得要有一个 render 函数,ok 配上,先来个标题组件 Title 和一个使用标题的 App 的组件吧。

可以对照完整的 demo 查看一下内容,demo。

var App = RD.extend({
  render(h) {
    return (
      
</div> ) } }) var Title = RD.extend({ render(h) { return ( <p className='title'>{this.title}</p> ) }, data(){ return { title:'这是个标题' } } })</code></pre> <p>这里就不说明 <code>JSX</code> 语法了,可以在 <code>babel</code> 上看下转码的结果,点击查看。</p> <p>至于 <code>render</code> 的参数为什么是 <code>h</code> ?这是大部分人都认可这么做,所以我们这么做就好。</p> <p>根据 <code>JSX</code> 的语法,我们需要实现一个创建虚拟节点的方法,也就是 <code>render</code> 需要传入的参数 <code>h</code> 。</p> <p>ok 实现一下,我们编写一个插件使用 <code>RD.use</code> 来实现对于实例的扩展</p> <pre><code>// demo/jsxPlugin/index.js export default { install(RD) { RD.prototype.$createElement = function (tag, properties, ...children) { return createElement(this, tag, properties, ...children) } RD.prototype.render = function () { return this.$option.render.call(this, this.$createElement.bind(this)) } } }</code></pre> <p>我们把具体的处理逻辑放在 <code>createElement</code> 这个方法中,而实例下的 <code>$createElement</code> 仅仅是为了把当前对象 <code>this</code> 传入这个函数中。</p> <p>接着我们把传入的 <code>render</code> 方法包装一下,挂载到实例的 <code>render</code> 方法下,我们先假设这个 <code>createElement</code> 能生成一个树结构,这样调用 实例下的 <code>render()</code> ,就能获得一个节点树。</p> <p>注:这里获得的并不是虚拟节点树,节点树需要涉及子组件,我们要确保这个节点树仅仅和当前实例相关,不然会比较麻烦,暂且叫它是节点模板。</p> <p>ok 我们可以想象一下这节点模板会长什么样?</p> <p>参考虚拟节点的库后,得到这样一个结构:</p> <pre><code>{ tagName: 'div', properties: {className: 'todo-wrap'}, children:[ tagName:'component-1',// 后面的 1 是扩展出来的类的 cid ,每个类都有一个单独的 cid parent: App, isComponent: true, componentClass: Title properties: {}, children: [] ] }</code></pre> <p>原有标签的处理虚拟节点的库已经帮我们做了,我们来实现一下组件的节点:</p> <pre><code>// demo/jsxPulgin/createElemet.js import {h, VNode} from 'virtual-dom' export default function createElement(ctx, tag, properties, ...children) { if (typeof tag === 'function' || typeof tag === 'object') { let node = new VNode() // 构建一个空的虚拟节点,带上组件的相关信息 node.tagName = `component-${tag.cid}` node.properties = properties // prop node.children = children // 组件的子节点,也就是 slot 这里并没有实现 node.parent = ctx // 父节点信息 node.isComponent = true // 用于判断是否是组件 node.componentClass = tag // 组件的类 return node } return h(tag, properties, children) // 一般标签直接调用库提供的方法生成 }</code></pre> <p>现在我们可以通过实例的 <code>render</code> 方法获取到了一个节点模板,但需要注意的是:这个仅仅只能算是通过 <code>JSX</code> 语法获取的一个模板,并没有转换为真正的虚拟节点,这是一个节点模板,当把其中的组件节点给替换掉就能得到真正的虚拟节点树。</p> <p>捋一捋我们现在有的:</p> <ol> <li>实例的 <code>render</code> 函数</li> <li>可以通过 <code>render</code> 函数生成的一个节点模板</li> </ol> <p>接着来实现一个方法,用于将节点模板转化为虚拟节点树,具体过程看代码中的注释</p> <pre><code>// demo/jsxPlugin/getTree.js function extend(source, extend) { for (let key in extend) { source[key] = extend[key] } return source } function createTree(template) { // 由于虚拟节点只接受通过 VNode 创建的对象 // 并且为了保持模板不被污染,所以新创建一个节点 let tree = extend(new VNode(), template) if (template && template.children) { // 遍历所有子节点 tree.children = template.children.map(node => { let treeNode = node // 如果是组件,则用保存的类实例化一个 RD 对象 if (node.isComponent) { // 确定 parent 实例以及 初始化 prop node.component = new node.componentClass({parent: node.parent, propData: node.properties}) // 将模板对应的节点模板指向实例的节点模板,实例下的 $vnode 用于存放节点模板 // 这样就将父组件中的组件节点替换为组件的节点模板,然后递归子组件,直到所有的组件节点都转换为了虚拟节点 // 这里使用了 $createComponentVNode 来获取节点模板,下一步我们就会实现它 treeNode = node.component.$vnode = node.component.$createComponentVNode(node.properties) // 如果是组件节点,则保存一个字段在虚拟节点下,用于区分普通节点 treeNode.component = node.component } if (treeNode.children) { // 递归生成虚拟节点树 treeNode = createTree(treeNode) } if (node.isComponent) { // 将生成的虚拟节点树保存在实例的 _vnode 字段下 node.component._vnode = treeNode } return treeNode }) } return tree }</code></pre> <p>现在的流程是 <code>render => createElement => createTree</code> 生成了虚拟节点,<code>$createComponentVNode</code> 其实就是调用组件的 <code>render</code> 函数,现在我们写一个 <code>$patch</code> 方法,包装这个行为,并且通过 <code>$mount</code> 实现挂载到 <code>DOM</code> 节点的过程。</p> <pre><code>// demo/jsxPlugin/index.js import {create, diff, patch} from 'virtual-dom' import createElement from './createElement' export default { install(RD) { RD.$mount = function (el, rd) { // 获取节点模板 let template = rd.render.call(rd) // 初始化 prop rd.$initProp(rd.propData) // 生成虚拟节点树 rd.$patch(template) // 挂载到传入的 DOM 上 el.appendChild(rd.$el) } RD.prototype.$createElement = function (tag, properties, ...children) { return createElement(this, tag, properties, ...children) } RD.prototype.render = function () { return this.$option.render.call(this, this.$createElement.bind(this)) } // 对 render 的封装,用于获取节点模板 RD.prototype.$createComponentVNode = function (prop) { this.$initProp(prop) return this.render.call(this) } RD.prototype.$patch = function (newTemplate) { // 获取到虚拟节点树 let newTree = createTree(newTemplate) // 将生成 DOM 元素保存在 $el 下,create 为虚拟节点库提供,用于生成 DOM 元素 this.$el = create(newTree) // 保存节点模板 this.$vnode = newTemplate // 保存虚拟节点树 this._vnode = newTree } } }</code></pre> <p>ok 接着我们来调用一下</p> <pre><code>// demo/index.js import RD from '../src/index' import jsxPlugin from './jsxPlugin/index' import App from './component/App' import './index.scss' RD.use(jsxPlugin, RD) RD.$mount(document.getElementById('app'), App)</code></pre> <p>到目前为止,我们仅仅是通过了页面的组成显示出了一个页面,并没有实现数据的绑定,但是有了 <code>RD</code> 的支持,我们可以很简单的实现这种由数据的变化导致视图变化的效果,加几段代码即可</p> <pre><code>// demo/jsxPlugin/index.js import {create, diff, patch} from 'virtual-dom' import createElement from './createElement' import getTree from './getTree' export default { install(RD) { RD.$mount = function (el, rd) { let template = null rd.$initProp(rd.propData) // 监听 render 所需要用的数据,当用到的数据发生变化的时候触发回调,也就是第二个参数 // 回调的的参数新的节点模板(也就是 $watch 第一个函数参数的返回值) // 回调触发 $patch rd.$renderWatch = rd.$watch(() => { template = rd.render.call(rd) return template }, (newTemplate) => { rd.$patch(newTemplate) }) rd.$patch(template) el.appendChild(rd.$el) } RD.prototype.$createElement = function (tag, properties, ...children) { return createElement(this, tag, properties, ...children) } RD.prototype.render = function () { return this.$option.render.call(this, this.$createElement.bind(this)) } RD.prototype.$createComponentVNode = function (prop) { let template = null this.$initProp(prop) // 监听 render 所需要用的数据,当用到的数据发生变化的时候触发 $patch this.$renderWatch = this.$watch(() => { template = this.render.call(this) return template }, (newTemplate) => { this.$patch(newTemplate) }) return template } RD.prototype.$patch = function (newTemplate) { // 由于是新创建和更新都在同一个函数中处理了 // 这里的 createTree 是需要条件判断调用的 // 所以这里的 getTree 就先认为是获取虚拟节点,之后再说 // $vnode 保存着节点模板,对于更新来说,这个就是旧模板 let newTree = getTree(newTemplate, this.$vnode) // _vnode 是原来的虚拟节点,如果没有的话就说明是第一次创建,就不需要走 diff & patch if (!this._vnode) { this.$el = create(newTree) } else { this.$el = patch(this.$el, diff(this._vnode, newTree)) } // 更新保存的变量 this.$vnode = newTemplate this._vnode = newTree this.$initDOMBind(this.$el, newTemplate) } // 由于组件的更新需要一个 $el ,所以 $initDOMBind 在每次 $patch 之后都需要调用,确定子组件绑定的元素 // 这里需要明确的是,由于模板必须使用一个元素包裹,所以父组件的状态改变时,父组件的 $el 是不会变的 // 需要变的仅仅是子组件的 $el 绑定,所以这个方法是向下进行的,不回去关注父组件以上的组件 RD.prototype.$initDOMBind = function (rootDom, vNodeTemplate) { if (!vNodeTemplate.children || vNodeTemplate.children.length === 0) return for (let i = 0, len = vNodeTemplate.children.length; i < len; i++) { if (vNodeTemplate.children[i].isComponent) { vNodeTemplate.children[i].component.$el = rootDom.childNodes[i] this.$initDOMBind(rootDom.childNodes[i], vNodeTemplate.children[i].component.$vnode) } else { this.$initDOMBind(rootDom.childNodes[i], vNodeTemplate.children[i]) } } } } }</code></pre> <p>ok 现在我们大概实现了一个 <code>MVVM</code> 框架,缺的仅仅是 <code>getTree</code> 这个获取虚拟节点树的方法,我们来实现一下。</p> <p>首先,<code>getTree</code> 需要传入两个参数,分别是新老节点模板,所以当老模板不存在时,走原来的逻辑即可</p> <pre><code>// demo/jsxPlugin/getTree.js function deepClone(node) { if (node.type === 'VirtualNode') { let children = [] if (node.children && node.children.length !== 0) { children = node.children.map(node => deepClone(node)) } let cloneNode = new VNode(node.tagName, node.properties, children) if (node.component) cloneNode.component = node.component return cloneNode } else if (node.type === 'VirtualText') { return new VText(node.text) } } export default function getTree(newTemplate, oldTemplate) { let tree = null if (!oldTemplate) { // 走原来的逻辑 tree = createTree(newTemplate) } else { // 走更新逻辑 tree = changeTree(newTemplate, oldTemplate) } // 确保给出一份完全新的虚拟节点树,我们克隆一份返回 return deepClone(tree) } // 具体的更新逻辑 function changeTree(newTemplate, oldTemplate) { let tree = extend(new VNode(), newTemplate) if (newTemplate && newTemplate.children) { // 遍历新模板的子节点 tree.children = newTemplate.children.map((node, index) => { let treeNode = node let isNewComponent = false if (treeNode.isComponent) { // 出于性能考虑,老节点模板中相同的 RD 类,就使用它 node.component = getOldComponent(oldTemplate.children, treeNode.componentClass.cid) if (!node.component) { // 在老模板中没有找到,就生成一个,与 createTree 中一致 node.component = new node.componentClass({parent: node.parent, propData: node.properties}) node.component.$vnode = node.component.$createComponentVNode(node.properties) treeNode = node.component.$vnode treeNode.component = node.component isNewComponent = true } else { // 更新复用组件的 prop node.component.$initProp(node.properties) // 直接引用组件的虚拟节点树 treeNode = node.component._vnode // 保存组件的实例 treeNode.component = node.component } } if (treeNode.children && treeNode.children.length !== 0) { if (isNewComponent) { // 如果是新的节点,直接调用 createTree treeNode = createTree(treeNode) } else { // 当递归的时候,有时可能出现老模板没有的情况,比如递归新节点的时候 // 所以需要判断 oldTemplate 的情况 if (oldTemplate && oldTemplate.children) { treeNode = changeTree(treeNode, oldTemplate.children[index]) } else { treeNode = createTree(treeNode) } } } if (isNewComponent) { node.component._vnode = treeNode } return treeNode }) // 注销在老模板中没有被复用的组件,释放内存 if (oldTemplate && oldTemplate.children.length !== 0) for (let i = 0, len = oldTemplate.children.length; i < len; i++) { if (oldTemplate.children[i].isComponent && !oldTemplate.children[i].used) { oldTemplate.children[i].component.$destroy() } } } return tree } // 获取在老模板中可服用的实例 function getOldComponent(list = [], cid) { for (let i = 0, len = list.length; i < len; i++) { if (!list[i].used && list[i].isComponent && list[i].componentClass.cid === cid) { list[i].used = true return list[i].component } } }</code></pre> <p>ok 整个 <code>MVVM</code> 框架实现,具体的效果可以把整个项目啦下来,执行 <code>npm run start:demo</code> 即可。上诉所有的代码都在 <code>demo</code> 中。</p> <p>我们来统计下我们一共写了几行代码来实现这个 <code>MVVM</code> 的框架:</p> <ul> <li>createElement.js 22行</li> <li>getTree.js 111行</li> <li>jsxPubgin/index.js 65行</li> </ul> <p>所以我们仅仅使用了 <code>22 + 111 + 65 = 198</code> 行代码实现了一个 <code>MVVM</code> 的框架,可以说是很少了。</p> <p>可能有的同学会说这还不算使用 <code>RD</code> 和虚拟节点库呢?是的我们并没有算上,因为这两个库的功能足够的独立,即使库变动了,实现相应的 <code>api</code> 用上面的代码我们同样能够实现,所以黑盒里的代码我们不算。<br>同样的我们也可以这么说,我们使用 <code>198</code> 行的代码连接了 <code>JSX/VNode/RD</code> 实现了一个 <code>MVVM</code> 框架。</p> <h3>谈谈感想</h3> <p>在研究 <code>Vue</code> 源码的过程中,在代码里看到了不少 <code>SSR</code> 和 <code>WEEX</code> 的判断,个人觉得这个没必要。这会导致 <code>Vue</code> 不论在哪段使用都会有较多的代码冗余。我认为一个理想的框架应该是足够的可配置的,至少对于开发人员来说应该如此。</p> <p>所以我觉得应该想 <code>react</code> 那样,在开发哪端的项目就引入相应的库即可,而不是将代码全部都聚合到同一个库中。</p> <p>以下我认为是可以做的,比如在开发 <code>web</code> 应用时,这样写</p> <pre><code>import vue from 'vue' import vue-dom from 'vue-dom' vue.use(vue-dom)</code></pre> <p>在开发 <code>WEEX</code> 应用时:</p> <pre><code>import vue from 'vue' import vue-dom from 'vue-weex' vue.use(vue-weex)</code></pre> <p>在开发 <code>SSR</code> 时:</p> <pre><code>import vue from 'vue' import vue-dom from 'vue-ssr' vue.use(vue-ssr)</code></pre> <p>当然如果说非要一套代码统一 <code>3</code> 端</p> <pre><code>import vue from 'vue' import vue-dom from 'vue-dynamic-import' vue.use(vue-dynamic-import)</code></pre> <p><code>vue-dynamic-import</code> 这个组件用于环境判断,动态导入相应环境的插件。</p> <p>这种想法也是我想把 <code>RD</code> 给独立出来的原因,一个模块足够的独立,让环境的判断交给程序员来决定,因为大部分项目是仅仅需要其中的一个功能,而不需要全部的功能的。</p> <p>以上,更多关于 <code>Vue</code> 的内容,已经关于 <code>RD</code> 的编写过程,可以到我的博客查看</p> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1177163015628337152"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(mvvm,vue.js)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1835512920797179904.htm" title="element实现动态路由+面包屑" target="_blank">element实现动态路由+面包屑</a> <span class="text-muted">软件技术NINI</span> <a class="tag" taget="_blank" href="/search/vue%E6%A1%88%E4%BE%8B/1.htm">vue案例</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>el-breadcrumb是ElementUI组件库中的一个面包屑导航组件,它用于显示当前页面的路径,帮助用户快速理解和导航到应用的各个部分。在Vue.js项目中,如果你已经安装了ElementUI,就可以很方便地使用el-breadcrumb组件。以下是一个基本的使用示例:安装ElementUI(如果你还没有安装的话):你可以通过npm或yarn来安装ElementUI。bash复制代码npmi</div> </li> <li><a href="/article/1835437775344726016.htm" title="博客网站制作教程" target="_blank">博客网站制作教程</a> <span class="text-muted">2401_85194651</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/maven/1.htm">maven</a> <div>首先就是技术框架:后端:Java+SpringBoot数据库:MySQL前端:Vue.js数据库连接:JPA(JavaPersistenceAPI)1.项目结构blog-app/├──backend/│├──src/main/java/com/example/blogapp/││├──BlogApplication.java││├──config/│││└──DatabaseConfig.java</div> </li> <li><a href="/article/1835331375377510400.htm" title="【前端】vue 报错:The template root requires exactly one element" target="_blank">【前端】vue 报错:The template root requires exactly one element</a> <span class="text-muted">程序员-张师傅</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>【前端】vue报错:Thetemplaterootrequiresexactlyoneelement在Vue.js中,当你遇到错误“Thetemplaterootrequiresexactlyoneelement”时,这通常意味着你的Vue组件的模板(template)根节点不是单一的元素。Vue要求每个组件的模板必须有一个根元素来包裹所有的子元素。这个错误通常出现在以下几种情况:模板中有多个并行</div> </li> <li><a href="/article/1835249513875468288.htm" title="说说在 Vue.js 中如何实现组件间通信" target="_blank">说说在 Vue.js 中如何实现组件间通信</a> <span class="text-muted">deniro</span> <div>1用法假设父组件的模板包含子组件,我们可以通过props来正向地把数据从父组件传递给子组件。props可以是字符串数组,也可以是对象。html:js:Vue.component('deniro-component',{props:['message'],template:'{{message}}'});varapp=newVue({el:'#app',data:{}});渲染结果:"嫦娥四号"成功</div> </li> <li><a href="/article/1835019650895802368.htm" title="python基于django/flask的NBA球员大数据分析与可视化python+java+node.js" target="_blank">python基于django/flask的NBA球员大数据分析与可视化python+java+node.js</a> <span class="text-muted">QQ_511008285</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/django/1.htm">django</a><a class="tag" taget="_blank" href="/search/flask/1.htm">flask</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a> <div>前端开发框架:vue.js数据库mysql版本不限后端语言框架支持:1java(SSM/springboot)-idea/eclipse2.Nodejs+Vue.js-vscode3.python(flask/django)--pycharm/vscode4.php(thinkphp/laravel)-hbuilderx数据库工具:Navicat/SQLyog等都可以本文针对NBA球员的大数据进行</div> </li> <li><a href="/article/1835019524521422848.htm" title="Java基于spring boot的国产电影数据分析与可视化python+java+node.js" target="_blank">Java基于spring boot的国产电影数据分析与可视化python+java+node.js</a> <span class="text-muted">QQ_511008285</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/django/1.htm">django</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/flask/1.htm">flask</a> <div>前端开发框架:vue.js数据库mysql版本不限后端语言框架支持:1java(SSM/springboot)-idea/eclipse2.Nodejs+Vue.js-vscode3.python(flask/django)--pycharm/vscode4.php(thinkphp/laravel)-hbuilderx数据库工具:Navicat/SQLyog等都可以  该系统使用进行大数据处理和</div> </li> <li><a href="/article/1834955336226795520.htm" title="Vue插槽:提升Vue组件灵活性的利器" target="_blank">Vue插槽:提升Vue组件灵活性的利器</a> <span class="text-muted">anyup_前端梦工厂</span> <a class="tag" taget="_blank" href="/search/Vue.js/1.htm">Vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>一.介绍什么是插槽插槽是Vue.js中一种强大的组件封装机制,用于在组件间复用可以动态填充的内容。简而言之,插槽允许我们在组件的模板中定义一些可变的区域,在使用组件时,可以灵活地填充不同的内容进入这些区域。当我们的组件有一些需要在使用组件时才能确定的内容时,比如按钮、文字、图标等,使用插槽可以非常方便地将这些内容传递给组件。二.基础插槽1.单个插槽单个插槽也可以称为默认插槽(DefaultSlot</div> </li> <li><a href="/article/1834943489872326656.htm" title="Android MVVM 架构应用实现(2)" target="_blank">Android MVVM 架构应用实现(2)</a> <span class="text-muted">渊Y</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a> <div>Repository类:实现BmobRepository类,作为HomeViewModel的数据提供方。BmobRepository类中有一个挂起函数getAllRecommendLibrary(libraryRecommendData:MutableLiveData)用来获取云数据库中的数据,函数的参数是LiveData,在获取数据后,利用setValue通知View展示数据。classBmob</div> </li> <li><a href="/article/1834920164567642112.htm" title="前端同学必备:教你如何安装、使用Chrome的vue-devtools插件" target="_blank">前端同学必备:教你如何安装、使用Chrome的vue-devtools插件</a> <span class="text-muted">界忆</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E7%BC%96%E7%A8%8B/1.htm">前端编程</a><a class="tag" taget="_blank" href="/search/Vue-devtools%E6%8F%92%E4%BB%B6/1.htm">Vue-devtools插件</a><a class="tag" taget="_blank" href="/search/chrome/1.htm">chrome</a><a class="tag" taget="_blank" href="/search/devtools/1.htm">devtools</a> <div>I.介绍vue-devtools插件Vue-devtools是一个Chrome浏览器插件,它是一个浏览器调试工具,用于开发Vue.js应用程序。它可以用于Vue.js应用程序的调试,可以更好地了解应用程序的结构和状态,以及帮助快速修复代码错误。Vue-devtools插件的作用和优势如下:1.调试Vue.js应用程序:Vue-devtools是一个强大的调试工具,可以帮助开发人员正确地调试应用程序</div> </li> <li><a href="/article/1834880085786718208.htm" title="python毕业设计作品:python闲置物品二手交易平台系统设计与实现毕业设计源代码(Django框架)" target="_blank">python毕业设计作品:python闲置物品二手交易平台系统设计与实现毕业设计源代码(Django框架)</a> <span class="text-muted">黄菊华老师</span> <a class="tag" taget="_blank" href="/search/%E6%AF%95%E8%AE%BE%E8%B5%84%E6%96%99/1.htm">毕设资料</a><a class="tag" taget="_blank" href="/search/python%E4%BA%8C%E6%89%8B%E4%BA%A4%E6%98%93%E5%B9%B3%E5%8F%B0%E7%B3%BB%E7%BB%9F/1.htm">python二手交易平台系统</a> <div>博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、PPT、论文模版等项目都录了发布和功能操作演示视频;项目的界面和功能都可以定制,包安装运行!!!如果需要联系我,可以在CSD</div> </li> <li><a href="/article/1834831805400838144.htm" title="Android应用架构 — 从MVC到MVVM,基于android的app开发" target="_blank">Android应用架构 — 从MVC到MVVM,基于android的app开发</a> <span class="text-muted">m0_66264134</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91/1.htm">移动开发</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>角色划分Model:用来保存程序的数据状态,比如数据存储,网络请求等。View:GUI组件构成,向用户展示Model中的数据。Controller:连接用户和系统,响应交互,传递数据。解决的问题MVC最重要的目的并不是规定各个模块应该如何交互和联系,而是将原有的混乱的应用程序划分出合理的层级,把以往一团混乱的代码,按照展示层和领域层分成两个部分。这种分离使得位于领域层中的领域对象可以不需要对展示层</div> </li> <li><a href="/article/1834831424239267840.htm" title="一文说透 Android 应用架构 MVC、MVP、MVVM 和 组件化,Android基础入门教程" target="_blank">一文说透 Android 应用架构 MVC、MVP、MVVM 和 组件化,Android基础入门教程</a> <span class="text-muted">Java后时代</span> <a class="tag" taget="_blank" href="/search/2024%E5%B9%B4%E7%A8%8B%E5%BA%8F%E5%91%98%E5%AD%A6%E4%B9%A0/1.htm">2024年程序员学习</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/mvc/1.htm">mvc</a> <div>然后,就是我们的View层的代码,同样,我对代码做了删减:@Route(path=BaseConstants.EYEPETIZER_MENU)publicclassHomeActivityextendsCommonActivityimplementsHomeContract.IView{//实例化PresenterprivateHomeContract.IPresenterpresenter;{p</div> </li> <li><a href="/article/1834768522685804544.htm" title="uni-app开发微信小程序" target="_blank">uni-app开发微信小程序</a> <span class="text-muted">hong161688</span> <a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">小程序</a> <div>uni-app是一个使用Vue.js开发所有前端应用的框架,它支持编译到iOS、Android、H5、以及各种小程序(微信/支付宝/百度/字节跳动/QQ/京东等)平台。使用uni-app开发微信小程序,可以充分利用Vue.js的开发效率和小程序平台的原生能力,实现跨平台的高效开发。以下将详细介绍使用uni-app开发微信小程序的全过程,包括项目搭建、开发、调试、测试及发布等环节,内容将尽量达到或超</div> </li> <li><a href="/article/1834756301549301760.htm" title="使用 uni-app 开发微信小程序:深入教程与技巧" target="_blank">使用 uni-app 开发微信小程序:深入教程与技巧</a> <span class="text-muted">代码伐木匠</span> <a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0%E6%9C%AC/1.htm">笔记本</a><a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/notepad%2B%2B/1.htm">notepad++</a> <div>使用uni-app开发微信小程序:深入教程与技巧uni-app是一个使用Vue.js语法开发跨平台应用的框架,能够编译到iOS、Android、H5、微信小程序等多个平台。通过uni-app,你可以一套代码同时生成多个端的应用,极大提升开发效率。本文将带你深入了解如何使用uni-app开发微信小程序,并提供大量实践经验与技巧。1.环境配置与项目创建要开始使用uni-app开发微信小程序,首先需要搭</div> </li> <li><a href="/article/1834738272555855872.htm" title="Vue Router push方法的使用" target="_blank">Vue Router push方法的使用</a> <span class="text-muted">hzw0510</span> <a class="tag" taget="_blank" href="/search/Vue/1.htm">Vue</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>VueRouterpush方法的使用this.$router.push是VueRouter提供的一个方法,用于在Vue.js应用中进行编程式导航。它的作用是将用户导航到应用中的不同路由。基本作用this.$router.push方法会在浏览器历史记录中添加一个新的记录,并导航到指定的路由。它的工作方式类似于点击一个组件,或者在浏览器中手动输入URL后点击回车。使用示例以下是一些使用this.$ro</div> </li> <li><a href="/article/1834688618837405696.htm" title="Android面试题" target="_blank">Android面试题</a> <span class="text-muted">1b16bebb1c3c</span> <div>ListView和RecyclerView区别参考链接:https://blog.csdn.net/shu_lan...既然RecyclerView在很多方面能取代ListView,Google为什么没把ListView划上一条过时的横线?答案:可以沿着回收机制来回答。ListView采用的是RecyclerBin的回收机制在一些轻量级的List显示时效率更高你用过MVP和MVVM的区别参考链接:</div> </li> <li><a href="/article/1834671207056764928.htm" title="组件通信——provide 和 inject 实现爷孙组件通信" target="_blank">组件通信——provide 和 inject 实现爷孙组件通信</a> <span class="text-muted">你不讲 wood</span> <a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>provide和inject实现爷孙组件通信介绍provide和inject是Vue.js提供的一种在组件之间共享数据的机制,它允许在组件树中的任何地方注入依赖项。这对于跨越多个层级的组件间通信特别有用,因此无需手动将prop数据逐层传递下去。provide:在一个组件中使用provide方法来定义要提供的数据或方法。provide方法返回一个对象,该对象包含了要提供的数据或方法。inject:在</div> </li> <li><a href="/article/1834655323768582144.htm" title="vue.js在js里获取属性,触发vue.js内的方法" target="_blank">vue.js在js里获取属性,触发vue.js内的方法</a> <span class="text-muted">摸鱼的张三</span> <a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/flutter/1.htm">flutter</a> <div>在script标签内把appVue设置varvarappVue=newVue({})appVue不能跨标签也就是说不能这样写varappVue=newVue({})console.log(appVue)上面这个是错的varappVue=newVue({})console.log(appVue)这个是vue2.js的版本这样写可以vue3.js是没有的然后拿到appVue就可以绑定原生事件触发app</div> </li> <li><a href="/article/1834631489283780608.htm" title="Vue 图片预览功能实现指南" target="_blank">Vue 图片预览功能实现指南</a> <span class="text-muted">繁依Fanyi</span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>1.介绍在现代web应用程序中,图片预览功能提升了用户体验,使用户可以在上传图片之前查看图片内容。本文将详细介绍如何在Vue.js应用中实现图片预览功能,包括基本实现、进阶功能、与ElementUI的集成、常见优化技巧以及与其他库的结合使用。2.基本功能实现2.1环境准备确保你的开发环境已经配置好,包括VueCLI和Node.js。如果还没有安装VueCLI,你可以通过以下命令安装:npminst</div> </li> <li><a href="/article/1834617504568274944.htm" title="前后端分离,Asp.net core webapi 如何配置跨域" target="_blank">前后端分离,Asp.net core webapi 如何配置跨域</a> <span class="text-muted">代码掌控者</span> <a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/core/1.htm">core</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/core/1.htm">core</a><a class="tag" taget="_blank" href="/search/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/1.htm">经验分享</a><a class="tag" taget="_blank" href="/search/c%23/1.htm">c#</a> <div>前言可以说,前后端分离已经成为当今信息系统项目开发的主流软件架构模式,微服务的出现,让前后端分离发展更是迅速,大量优秀的前端框架如vue.js、react的出现,也让前后端分离趋势加快。所谓的前后端分离软件架构模式,就是指将前端和后端的开发完全分离,后端负责提供API接口和数据处理,而前端通过各种现代的JavaScript技术如AJAX或者Fetch等,来调用后端提供的API接口获取数据,从而构建</div> </li> <li><a href="/article/1834610822148616192.htm" title="Uni-app 开发微信小程序" target="_blank">Uni-app 开发微信小程序</a> <span class="text-muted">vvvae1234</span> <a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a> <div>随着移动互联网的发展,微信小程序已经成为一种流行的应用开发模式。Uni-app作为一种跨平台的开发框架,使用Vue.js语法,能够方便快速地开发出微信小程序、H5、App等多端应用。本指南将引导您从环境配置到实战案例开发,帮助您快速掌握使用Uni-app开发微信小程序的技巧。2.Uni-app概述2.1什么是Uni-app?Uni-app是一个使用Vue.js语法的跨平台开发框架,允许开发者用一套</div> </li> <li><a href="/article/1834590657881141248.htm" title="前后端时间转换的那些常见问题及处理方法" target="_blank">前后端时间转换的那些常见问题及处理方法</a> <span class="text-muted">繁依Fanyi</span> <a class="tag" taget="_blank" href="/search/%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F/1.htm">状态模式</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/github/1.htm">github</a> <div>在现代的Web开发中,前后端分离的架构已经成为主流,尤其是在SpringBoot和Vue.js的组合中。开发者在这种架构下经常遇到的一个问题就是如何处理时间的转换和显示。前端和后端对时间的处理方式不同,可能会导致时间在传递过程中出现问题,比如时区不同步、格式不一致等。因此,本文将详细讨论在SpringBoot+Vue前后端分离架构中如何处理时间转换问题,并提供一些解决方案。一、前后端时间处理的常见</div> </li> <li><a href="/article/1834480753681985536.htm" title="cross-plateform 跨平台应用程序-06-uni-app 介绍" target="_blank">cross-plateform 跨平台应用程序-06-uni-app 介绍</a> <span class="text-muted">知识分享官</span> <a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a> <div>详细介绍一下uni-app?whatuni-app是一个使用Vue.js开发所有前端应用的框架,开发者编写一次代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/京东/美团/钉钉/淘宝)、快应用等多个平台。以下是uni-app的一些核心特性和优势:使用Vue.js开发:uni-app基于Vue.js,这意味着如果你已经熟悉Vue.js</div> </li> <li><a href="/article/1834439914788319232.htm" title="【Java设计模式】模型 - 视图 - 视图模型模式" target="_blank">【Java设计模式】模型 - 视图 - 视图模型模式</a> <span class="text-muted">道长不会写代码</span> <a class="tag" taget="_blank" href="/search/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">Java设计模式</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>文章目录【Java设计模式】模型-视图-视图模型模式一、概述二、详细解释及实际示例三、Java中模型-视图-视图模型模式的编程示例四、何时在Java中使用模型-视图-视图模型模式五、模型-视图-视图模型模式在Java中的实际应用六、模型-视图-视图模型模式的好处和权衡七、源码下载【Java设计模式】模型-视图-视图模型模式一、概述Java中模型-视图-视图模型(MVVM)模式的目的是通过将应用程序</div> </li> <li><a href="/article/1834263549615108096.htm" title="Jetpack Compose 架构如何选?MVP 、 MVVM 还是 MVI" target="_blank">Jetpack Compose 架构如何选?MVP 、 MVVM 还是 MVI</a> <span class="text-muted">一朵白山茶</span> <a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a><a class="tag" taget="_blank" href="/search/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/1.htm">经验分享</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div>[](()前期准备:Model层=======================================================================其实无论MVX中X如何变化,Model都可以用同一套实现。我们先定义一个DataRepository,用于从wanandroid获取搜索结果。后文Sample中的Model层都基于此Repo实现@ViewModelScoped</div> </li> <li><a href="/article/1834255477148577792.htm" title="Android Compose UI (二) 常规MVI操作" target="_blank">Android Compose UI (二) 常规MVI操作</a> <span class="text-muted">CreeLu</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a> <div>文章目录1.概述2.MVI的变化概括3.ViewModel的变化4.Activity/Fragment/View的变化5.Toast/Dialog/底部提示等临时UI状态6.总结1.概述随着Android应用不断的演化,从最开始的MVC->MVP->MVVM,现在Google官方也有了MVI的示例,相比较MVVM来说有了一些变化,接下来跟着文章一起了解.(其实这篇文章主要是介绍MVI的,和Comp</div> </li> <li><a href="/article/1834250057449304064.htm" title="Jetpack Compose 架构如何选?MVP 、 MVVM 还是 MVI?" target="_blank">Jetpack Compose 架构如何选?MVP 、 MVVM 还是 MVI?</a> <span class="text-muted">goodhighting</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a> <div>首先,先看看不借助任何架构的Compose代码是怎样的?不使用架构的情况下,逻辑代码将与UI代码耦合在一起,在Compose中这种弊端显得尤为明显。常规Android开发默认引入了MVC思想,XML的布局方式使得UI层与逻辑层有了初步的解耦。但是Compose中,布局和逻辑同样都使用Kotlin实现,当布局中夹了杂逻辑,界限变得更加模糊。此外,ComposeUI中混入逻辑代码会带来更多的潜在隐患。</div> </li> <li><a href="/article/1834147716041633792.htm" title="从学习vue到uni-app的心得感悟" target="_blank">从学习vue到uni-app的心得感悟</a> <span class="text-muted">crazy_章鱼哥</span> <a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>前言你是否想过,只用一套代码,就能开发出适用于多个平台的前端应用?你是否想过,只用Vue.js这样一个简洁强大的框架,就能实现各种炫酷的功能和效果?你是否想过,只用uni-app这样一个神器,就能成为一个高手?如果你有这样的想法,那么就跟我一起来学习uni-app吧!uni-app是一个基于Vue.js的全端开发框架,它可以让你用一套代码,同时运行在H5、小程序、App等多个平台上。它具有跨平台、</div> </li> <li><a href="/article/1834134354851360768.htm" title="基于java+SpringBoot+Vue的小徐影城管理系统设计与实现" target="_blank">基于java+SpringBoot+Vue的小徐影城管理系统设计与实现</a> <span class="text-muted">paterWang</span> <a class="tag" taget="_blank" href="/search/Java%E7%B2%BE%E5%93%81%E6%AF%95%E8%AE%BE%E5%AE%9E%E6%88%98/1.htm">Java精品毕设实战</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1/1.htm">计算机毕业设计</a><a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>开发语言:Java数据库:MySQL技术:SpringBoot+MyBatis工具:IDEA/Ecilpse、Navicat、Maven系统简介小徐影城管理系统是一款基于Java、SpringBoot和Vue.js技术开发的影院管理系统,旨在为用户提供一个便捷、高效的在线购票和影院管理平台。系统通过B/S架构,实现了管理员和用户两端的功能操作,使得影院管理更加系统化、规范化。整体功能包含:电影信息</div> </li> <li><a href="/article/1834077372249370624.htm" title="vue前端性能优化之cdn的使用" target="_blank">vue前端性能优化之cdn的使用</a> <span class="text-muted">不cong明的亚子</span> <a class="tag" taget="_blank" href="/search/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/1.htm">性能优化</a><a class="tag" taget="_blank" href="/search/vue%2Belement/1.htm">vue+element</a><a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a> <div>优化原因项目中首页加载过慢,原因是js,css静态资源第一次加载的时间长vue.config.js'usestrict'......constcdn={js_cdn:['https://cdn.jsdelivr.net/npm/moment@2.27.0/moment.min.js','https://unpkg.com/vue@2.6.10/dist/vue.js','https://unpkg</div> </li> <li><a href="/article/108.htm" title="Nginx负载均衡" target="_blank">Nginx负载均衡</a> <span class="text-muted">510888780</span> <a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a><a class="tag" taget="_blank" href="/search/%E5%BA%94%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">应用服务器</a> <div>Nginx负载均衡一些基础知识: nginx 的 upstream目前支持 4 种方式的分配 1)、轮询(默认)       每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。 2)、weight       指定轮询几率,weight和访问比率成正比</div> </li> <li><a href="/article/235.htm" title="RedHat 6.4 安装 rabbitmq" target="_blank">RedHat 6.4 安装 rabbitmq</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/erlang/1.htm">erlang</a><a class="tag" taget="_blank" href="/search/rabbitmq/1.htm">rabbitmq</a><a class="tag" taget="_blank" href="/search/redhat/1.htm">redhat</a> <div>在 linux 下安装软件就是折腾,首先是测试机不能上外网要找运维开通,开通后发现测试机的 yum 不能使用于是又要配置 yum 源,最后安装 rabbitmq 时也尝试了两种方法最后才安装成功 机器版本: [root@redhat1 rabbitmq]# lsb_release LSB Version: :base-4.0-amd64:base-4.0-noarch:core</div> </li> <li><a href="/article/362.htm" title="FilenameUtils工具类" target="_blank">FilenameUtils工具类</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/FilenameUtils/1.htm">FilenameUtils</a><a class="tag" taget="_blank" href="/search/common-io/1.htm">common-io</a> <div>转载请出自出处:http://eksliang.iteye.com/blog/2217081 一、概述 这是一个Java操作文件的常用库,是Apache对java的IO包的封装,这里面有两个非常核心的类FilenameUtils跟FileUtils,其中FilenameUtils是对文件名操作的封装;FileUtils是文件封装,开发中对文件的操作,几乎都可以在这个框架里面找到。 非常的好用。 </div> </li> <li><a href="/article/489.htm" title="xml文件解析SAX" target="_blank">xml文件解析SAX</a> <span class="text-muted">不懂事的小屁孩</span> <a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a> <div>xml文件解析:xml文件解析有四种方式, 1.DOM生成和解析XML文档(SAX是基于事件流的解析) 2.SAX生成和解析XML文档(基于XML文档树结构的解析) 3.DOM4J生成和解析XML文档 4.JDOM生成和解析XML 本文章用第一种方法进行解析,使用android常用的DefaultHandler import org.xml.sax.Attributes; </div> </li> <li><a href="/article/616.htm" title="通过定时任务执行mysql的定期删除和新建分区,此处是按日分区" target="_blank">通过定时任务执行mysql的定期删除和新建分区,此处是按日分区</a> <span class="text-muted">酷的飞上天空</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div>使用python脚本作为命令脚本,linux的定时任务来每天定时执行 #!/usr/bin/python # -*- coding: utf8 -*- import pymysql import datetime import calendar #要分区的表 table_name = 'my_table' #连接数据库的信息 host,user,passwd,db = </div> </li> <li><a href="/article/743.htm" title="如何搭建数据湖架构?听听专家的意见" target="_blank">如何搭建数据湖架构?听听专家的意见</a> <span class="text-muted">蓝儿唯美</span> <a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a> <div>Edo Interactive在几年前遇到一个大问题:公司使用交易数据来帮助零售商和餐馆进行个性化促销,但其数据仓库没有足够时间去处理所有的信用卡和借记卡交易数据  “我们要花费27小时来处理每日的数据量,”Edo主管基础设施和信息系统的高级副总裁Tim Garnto说道:“所以在2013年,我们放弃了现有的基于PostgreSQL的关系型数据库系统,使用了Hadoop集群作为公司的数</div> </li> <li><a href="/article/870.htm" title="spring学习——控制反转与依赖注入" target="_blank">spring学习——控制反转与依赖注入</a> <span class="text-muted">a-john</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>       控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。   </div> </li> <li><a href="/article/997.htm" title="用spool+unixshell生成文本文件的方法" target="_blank">用spool+unixshell生成文本文件的方法</a> <span class="text-muted">aijuans</span> <a class="tag" taget="_blank" href="/search/xshell/1.htm">xshell</a> <div>例如我们把scott.dept表生成文本文件的语句写成dept.sql,内容如下:   set pages 50000;   set lines 200;   set trims on;   set heading off;   spool /oracle_backup/log/test/dept.lst;   select deptno||','||dname||','||loc </div> </li> <li><a href="/article/1124.htm" title="1、基础--名词解析(OOA/OOD/OOP)" target="_blank">1、基础--名词解析(OOA/OOD/OOP)</a> <span class="text-muted">asia007</span> <a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/1.htm">学习基础知识</a> <div>OOA:Object-Oriented Analysis(面向对象分析方法) 是在一个系统的开发过程中进行了系统业务调查以后,按照面向对象的思想来分析问题。OOA与结构化分析有较大的区别。OOA所强调的是在系统调查资料的基础上,针对OO方法所需要的素材进行的归类分析和整理,而不是对管理业务现状和方法的分析。   OOA(面向对象的分析)模型由5个层次(主题层、对象类层、结构层、属性层和服务层)</div> </li> <li><a href="/article/1251.htm" title="浅谈java转成json编码格式技术" target="_blank">浅谈java转成json编码格式技术</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/json%E7%BC%96%E7%A0%81/1.htm">json编码</a><a class="tag" taget="_blank" href="/search/java%E8%BD%AC%E6%88%90json%E7%BC%96%E7%A0%81/1.htm">java转成json编码</a> <div>json编码;是一个轻量级的数据存储和传输的语言       在java中需要引入json相关的包,引包方式在工程的lib下就可以了   JSON与JAVA数据的转换(JSON 即 JavaScript Object Natation,它是一种轻量级的数据交换格式,非   常适合于服务器与 JavaScript 之间的数据的交</div> </li> <li><a href="/article/1378.htm" title="web.xml之Spring配置(基于Spring+Struts+Ibatis)" target="_blank">web.xml之Spring配置(基于Spring+Struts+Ibatis)</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/web.xml/1.htm">web.xml</a><a class="tag" taget="_blank" href="/search/SSI/1.htm">SSI</a><a class="tag" taget="_blank" href="/search/spring%E9%85%8D%E7%BD%AE/1.htm">spring配置</a> <div>指定Spring配置文件位置 <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring-dao-bean.xml,/WEB-INF/spring-resources.xml, /WEB-INF/</div> </li> <li><a href="/article/1505.htm" title="Installing SonarQube(Fail to download libraries from server)" target="_blank">Installing SonarQube(Fail to download libraries from server)</a> <span class="text-muted">sunjing</span> <a class="tag" taget="_blank" href="/search/Install/1.htm">Install</a><a class="tag" taget="_blank" href="/search/Sonar/1.htm">Sonar</a> <div>1.  Download and unzip the SonarQube distribution 2.  Starting the Web Server The default port is "9000" and the context path is "/". These values can be changed in &l</div> </li> <li><a href="/article/1632.htm" title="【MongoDB学习笔记十一】Mongo副本集基本的增删查" target="_blank">【MongoDB学习笔记十一】Mongo副本集基本的增删查</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/mongodb/1.htm">mongodb</a> <div>一、创建复本集   假设mongod,mongo已经配置在系统路径变量上,启动三个命令行窗口,分别执行如下命令:   mongod --port 27017 --dbpath data1 --replSet rs0 mongod --port 27018 --dbpath data2 --replSet rs0 mongod --port 27019 -</div> </li> <li><a href="/article/1759.htm" title="Anychart图表系列二之执行Flash和HTML5渲染" target="_blank">Anychart图表系列二之执行Flash和HTML5渲染</a> <span class="text-muted">白糖_</span> <a class="tag" taget="_blank" href="/search/Flash/1.htm">Flash</a> <div>今天介绍Anychart的Flash和HTML5渲染功能   HTML5 Anychart从6.0第一个版本起,已经逐渐开始支持各种图的HTML5渲染效果了,也就是说即使你没有安装Flash插件,只要浏览器支持HTML5,也能看到Anychart的图形(不过这些是需要做一些配置的)。 这里要提醒下大家,Anychart6.0版本对HTML5的支持还不算很成熟,目前还处于</div> </li> <li><a href="/article/1886.htm" title="Laravel版本更新异常4.2.8-> 4.2.9 Declaration of ... CompilerEngine ... should be compa" target="_blank">Laravel版本更新异常4.2.8-> 4.2.9 Declaration of ... CompilerEngine ... should be compa</a> <span class="text-muted">bozch</span> <a class="tag" taget="_blank" href="/search/laravel/1.htm">laravel</a> <div>昨天在为了把laravel升级到最新的版本,突然之间就出现了如下错误: ErrorException thrown with message "Declaration of Illuminate\View\Engines\CompilerEngine::handleViewException() should be compatible with Illuminate\View\Eng</div> </li> <li><a href="/article/2013.htm" title="编程之美-NIM游戏分析-石头总数为奇数时如何保证先动手者必胜" target="_blank">编程之美-NIM游戏分析-石头总数为奇数时如何保证先动手者必胜</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BE%8E/1.htm">编程之美</a> <div> import java.util.Arrays; import java.util.Random; public class Nim { /**编程之美 NIM游戏分析 问题: 有N块石头和两个玩家A和B,玩家A先将石头随机分成若干堆,然后按照BABA...的顺序不断轮流取石头, 能将剩下的石头一次取光的玩家获胜,每次取石头时,每个玩家只能从若干堆石头中任选一堆,</div> </li> <li><a href="/article/2140.htm" title="lunce创建索引及简单查询" target="_blank">lunce创建索引及简单查询</a> <span class="text-muted">chengxuyuancsdn</span> <a class="tag" taget="_blank" href="/search/%E6%9F%A5%E8%AF%A2/1.htm">查询</a><a class="tag" taget="_blank" href="/search/%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95/1.htm">创建索引</a><a class="tag" taget="_blank" href="/search/lunce/1.htm">lunce</a> <div>import java.io.File; import java.io.IOException; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Docume</div> </li> <li><a href="/article/2267.htm" title="[IT与投资]坚持独立自主的研究核心技术" target="_blank">[IT与投资]坚持独立自主的研究核心技术</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/it/1.htm">it</a> <div>        和别人合作开发某项产品....如果互相之间的技术水平不同,那么这种合作很难进行,一般都会成为强者控制弱者的方法和手段.....        所以弱者,在遇到技术难题的时候,最好不要一开始就去寻求强者的帮助,因为在我们这颗星球上,生物都有一种控制其</div> </li> <li><a href="/article/2394.htm" title="flashback transaction闪回事务查询" target="_blank">flashback transaction闪回事务查询</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/%E9%97%AA%E5%9B%9E%E4%BA%8B%E5%8A%A1/1.htm">闪回事务</a> <div>   闪回事务查询有别于闪回查询的特点有以下3个: (1)其正常工作不但需要利用撤销数据,还需要事先启用最小补充日志。 (2)返回的结果不是以前的“旧”数据,而是能够将当前数据修改为以前的样子的撤销SQL(Undo SQL)语句。 (3)集中地在名为flashback_transaction_query表上查询,而不是在各个表上通过“as of”或“vers</div> </li> <li><a href="/article/2521.htm" title="Java I/O之FilenameFilter类列举出指定路径下某个扩展名的文件" target="_blank">Java I/O之FilenameFilter类列举出指定路径下某个扩展名的文件</a> <span class="text-muted">游其是你</span> <a class="tag" taget="_blank" href="/search/FilenameFilter/1.htm">FilenameFilter</a> <div>这是一个FilenameFilter类用法的例子,实现的列举出“c:\\folder“路径下所有以“.jpg”扩展名的文件。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 </div> </li> <li><a href="/article/2648.htm" title="C语言学习五函数,函数的前置声明以及如何在软件开发中合理的设计函数来解决实际问题" target="_blank">C语言学习五函数,函数的前置声明以及如何在软件开发中合理的设计函数来解决实际问题</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/c/1.htm">c</a> <div># include <stdio.h> int f(void) //括号中的void表示该函数不能接受数据,int表示返回的类型为int类型 { return 10; //向主调函数返回10 } void g(void) //函数名前面的void表示该函数没有返回值 { //return 10; //error 与第8行行首的void相矛盾 } in</div> </li> <li><a href="/article/2775.htm" title="今天在测试环境使用yum安装,遇到一个问题: Error: Cannot retrieve metalink for repository: epel. Pl" target="_blank">今天在测试环境使用yum安装,遇到一个问题: Error: Cannot retrieve metalink for repository: epel. Pl</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/centos/1.htm">centos</a> <div>今天在测试环境使用yum安装,遇到一个问题: Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again   处理很简单,修改文件“/etc/yum.repos.d/epel.repo”, 将baseurl的注释取消, mirrorlist注释掉。即可。 &n</div> </li> <li><a href="/article/2902.htm" title="单例模式" target="_blank">单例模式</a> <span class="text-muted">shuizhaosi888</span> <a class="tag" taget="_blank" href="/search/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/1.htm">单例模式</a> <div>单例模式      懒汉式 public class RunMain { /** * 私有构造 */ private RunMain() { } /** * 内部类,用于占位,只有 */ private static class SingletonRunMain { priv</div> </li> <li><a href="/article/3029.htm" title="Spring Security(09)——Filter" target="_blank">Spring Security(09)——Filter</a> <span class="text-muted">234390216</span> <a class="tag" taget="_blank" href="/search/Spring+Security/1.htm">Spring Security</a> <div>Filter 目录 1.1     Filter顺序 1.2     添加Filter到FilterChain 1.3     DelegatingFilterProxy 1.4     FilterChainProxy 1.5</div> </li> <li><a href="/article/3156.htm" title="公司项目NODEJS实践0.1" target="_blank">公司项目NODEJS实践0.1</a> <span class="text-muted">逐行分析JS源代码</span> <a class="tag" taget="_blank" href="/search/mongodb/1.htm">mongodb</a><a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a><a class="tag" taget="_blank" href="/search/ubuntu/1.htm">ubuntu</a><a class="tag" taget="_blank" href="/search/nodejs/1.htm">nodejs</a> <div>  一、前言         前端如何独立用nodeJs实现一个简单的注册、登录功能,是不是只用nodejs+sql就可以了?其实是可以实现,但离实际应用还有距离,那要怎么做才是实际可用的。         网上有很多nod</div> </li> <li><a href="/article/3283.htm" title="java.lang.Math" target="_blank">java.lang.Math</a> <span class="text-muted">liuhaibo_ljf</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/Math/1.htm">Math</a><a class="tag" taget="_blank" href="/search/lang/1.htm">lang</a> <div>System.out.println(Math.PI); System.out.println(Math.abs(1.2)); System.out.println(Math.abs(1.2)); System.out.println(Math.abs(1)); System.out.println(Math.abs(111111111)); System.out.println(Mat</div> </li> <li><a href="/article/3410.htm" title="linux下时间同步" target="_blank">linux下时间同步</a> <span class="text-muted">nonobaba</span> <a class="tag" taget="_blank" href="/search/ntp/1.htm">ntp</a> <div>今天在linux下做hbase集群的时候,发现hmaster启动成功了,但是用hbase命令进入shell的时候报了一个错误  PleaseHoldException: Master is initializing,查看了日志,大致意思是说master和slave时间不同步,没办法,只好找一种手动同步一下,后来发现一共部署了10来台机器,手动同步偏差又比较大,所以还是从网上找现成的解决方</div> </li> <li><a href="/article/3537.htm" title="ZooKeeper3.4.6的集群部署" target="_blank">ZooKeeper3.4.6的集群部署</a> <span class="text-muted">roadrunners</span> <a class="tag" taget="_blank" href="/search/zookeeper/1.htm">zookeeper</a><a class="tag" taget="_blank" href="/search/%E9%9B%86%E7%BE%A4/1.htm">集群</a><a class="tag" taget="_blank" href="/search/%E9%83%A8%E7%BD%B2/1.htm">部署</a> <div>ZooKeeper是Apache的一个开源项目,在分布式服务中应用比较广泛。它主要用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步、集群管理、配置文件管理、同步锁、队列等。这里主要讲集群中ZooKeeper的部署。   1、准备工作 我们准备3台机器做ZooKeeper集群,分别在3台机器上创建ZooKeeper需要的目录。   数据存储目录</div> </li> <li><a href="/article/3664.htm" title="Java高效读取大文件" target="_blank">Java高效读取大文件</a> <span class="text-muted">tomcat_oracle</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>  读取文件行的标准方式是在内存中读取,Guava 和Apache Commons IO都提供了如下所示快速读取文件行的方法:   Files.readLines(new File(path), Charsets.UTF_8);   FileUtils.readLines(new File(path));   这种方法带来的问题是文件的所有行都被存放在内存中,当文件足够大时很快就会导致</div> </li> <li><a href="/article/3791.htm" title="微信支付api返回的xml转换为Map的方法" target="_blank">微信支付api返回的xml转换为Map的方法</a> <span class="text-muted">xu3508620</span> <a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a><a class="tag" taget="_blank" href="/search/map/1.htm">map</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1api/1.htm">微信api</a> <div>举例如下: <xml>    <return_code><![CDATA[SUCCESS]]></return_code>    <return_msg><![CDATA[OK]]></return_msg>    <appid><</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>