1.vue for Java (vue4j) 快速体验

git仓库

https://gitee.com/ichiva_admin/vue4j-core.git

介绍

vue for java (vue4j) 是一个采用vue设计思想Java GUI框架,
软件在Javafx基础上扩展了双向绑定和组件化,实现了vue基于数据驱动的设计思想.
使用vue4j可以带来以下优势:

  • 更直观的组件化,更容易构建复杂的GUI
  • 数据驱动,避免Javafx必须使用主线程刷新UI带来的复杂性,可以更好的专注于业务

安装教程

vue4j 依赖Java8提供的Javafx

采用maven构建

    <dependencies>
        <dependency>
            <groupId>com.gome</groupId>
            <artifactId>vue4j-core</artifactId>
            <version>8.0-PREVIEW</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>xwintop-maven</id>
            <url>https://gitee.com/ichiva_admin/vue4j-core/tree/v8/repository</url>
        </repository>
    </repositories>

使用说明

  • hello world! 直接把xml写在代码中有点蠢,后续Java支持文本块的版本中还是可以尝试一下的,接下来我们会把xml放在fxml文件中试试
public class L1Bind extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Scene scene = Vue4jLoader.loadScene(new L1BindComponent(), 320, 200);
        stage.setScene(scene);
        stage.setTitle("直接fxml方式,小型组件勉强可用");
        stage.show();
    }
}

class L1BindComponent extends AbstractVue4jComponent {
    @Override
    public CharSequence render() {
        imports(VBox.class, Insets.class, Label.class, Button.class);
        return "<VBox alignment=\"CENTER\" spacing=\"20.0\" xmlns:fx=\"http://javafx.com/fxml\">\n" +
                "        <Label text=\"${welcomeText}\" />\n" +
                "        <Button text=\"Hello!\" onAction=\"#onHelloButtonClick\"/>\n" +
                "</VBox>";
    }

    @FXML
    StringProperty welcomeText = new SimpleStringProperty();

    @FXML
    void onHelloButtonClick(){
        welcomeText.set("hello world!");
    }
}
  • 简单的数据绑定
    Java代码
public class L1Z2Bind extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Scene scene = Vue4jLoader.loadScene(new L1Z2BindComponent(),320,600);
        stage.setScene(scene);
        stage.setTitle("简单的数据绑定");
        stage.show();
    }
}

@FXMLPath("/base/l1z2-view.fxml")
class L1Z2BindComponent extends AbstractVue4jComponent {
    @FXML
    StringProperty message = new SimpleStringProperty("简单数据绑定");
}

l1z2-view.fxml代码

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<?import javafx.geometry.Insets?>
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">

        <Label text="${message}" />
</VBox>
  • 样式绑定
    L3Style 代码
public class L3Style extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        L3StyleComponent component = new L3StyleComponent();
        Scene scene = Vue4jLoader.loadScene(component,320,600);
        stage.setScene(scene);
        stage.setTitle("样式绑定");
        stage.show();
    }
}

L3StyleComponent 代码

@FXMLPath("/base/l3-view.fxml")
public class L3StyleComponent extends AbstractVue4jComponent {

    @FXML
    StringProperty style = new SimpleStringProperty("-fx-text-fill: red;");

    @FXML
    void addBorder(){
        style.set(style.get() + "-fx-border-width: 1;-fx-border-style: solid;-fx-border-color: red");
    }
}

l3-view.fxml

<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">

        <Label text="打螺丝" style="${style}" />
        <Button text="添加边框" onAction="#addBorder" />
</VBox>
  • 类绑定

L3Z1StyleClass代码,为stage添加样式表

public class L3Z1StyleClass extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        L3Z1StyleClassComponent component = new L3Z1StyleClassComponent();
        Scene scene = Vue4jLoader.loadScene(component,320,600);
        scene.getStylesheets().add(L3Z1StyleClass.class.getResource("/css/LabeledTextTest.css").toExternalForm());
        stage.setScene(scene);
        stage.setTitle("类绑定");
        stage.show();
    }
}

LabeledTextTest.css 样式表

.yellowBackground{
    -fx-background-color: yellow;
}

.red{
    -fx-text-fill: red;
}


.redBorder{
    -fx-border-width: 1;
    -fx-border-style: solid;
    -fx-border-color: red
}

动态绑定类型

@FXMLPath("/base/l3z1-view.fxml")
public class L3Z1StyleClassComponent extends AbstractVue4jComponent {
    @FXML
    StringProperty message = new SimpleStringProperty("类型绑定");

    @FXML
    List<String> classList = FXCollections.observableArrayList();

    @FXML
    public void setRed(){
        String red = "red";
        if(!classList.contains(red)){
            classList.add(red);
        }else {
            classList.remove(red);
        }
    }

    @FXML
    public void yellowBackground(){
        String red = "yellowBackground";
        if(!classList.contains(red)){
            classList.add(red);
        }else {
            classList.remove(red);
        }
    }
    @FXML
    public void setBorder(){
        String red = "redBorder";
        if(!classList.contains(red)){
            classList.add(red);
        }else {
            classList.remove(red);
        }
    }

}

l3z1-view.fxml

<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
        <Label text="${message}" styleClass="${classList}" />

        <Button text="设置为红色" onAction="#setRed" />
        <Button text="设置为黄色背景"  onAction="#yellowBackground" />
        <Button text="设置为设置边框"  onAction="#setBorder" />
</VBox>
  • if条件渲染,条件渲染需要改变dom,因此需要主动调用update()
@FXMLPath("/base/l4-view.fxml")
public class L4IfComponent extends AbstractVue4jComponent {
    @FXML
    boolean flag = true;

    @FXML
    public void toggle(){
        flag = !flag;
        update();
    }
}

l4-view.fxml

<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
        <Label text="Puppet Master" if="${flag}" />
        <Button text="显示/隐藏" onAction="#toggle" />
</VBox>
  • for指令,集合渲染需要改变dom,因此需要主动调用update(),本列中可以实现动态添加群众演员

    L5ForComponent代码

@FXMLPath("/base/l5-view.fxml")
public class L5ForComponent extends AbstractVue4jComponent {
    @FXML
    public List<Actor> actors = new ArrayList<>(Arrays.asList(
            new Actor(1L,"张飞",28),
            new Actor(2L,"关羽",32),
            new Actor(3L,"刘备",36)
    ));

    @FXML
    void addActor(){
        long id = System.currentTimeMillis();
        actors.add(new Actor(id,"群众" + id,22));
        update();
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Actor{
        Long id;
        String name;
        int age;
    }
}

l5-view.fxml

<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
        <Label text="${controller.actors.get(index).getName()}" for="index : actors" />
        <Button text="添加群众演员" onAction="#addActor" />
</VBox>
  • for可对list和map集合进行渲染,list遍历出来的是列表的序号,map遍历出来的是key值,一般都需要配合表达式使用,表达式相当于在外部调用控制器的属性和方法,因此必须设置为public
  • 对map的遍历
    L5Z1ForComponent代码,LinkedHashMap可以保证map集合的顺序
@FXMLPath("/base/l5z1-view.fxml")
public class L5Z1ForComponent extends AbstractVue4jComponent {
    @FXML
    public Map<String,Actor> actors = new LinkedHashMap<String, Actor>(){
        {
            put("张飞",new Actor(1L,"张飞",28));
            put("关羽",new Actor(2L,"关羽",32));
            put("刘备",new Actor(3L,"刘备",36));
        }
    };

    @FXML
    void addActor(){
        long id = System.currentTimeMillis();
        String name = "群众" + id;
        actors.put(name,new Actor(id, name,22));
        update();
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Actor{
        Long id;
        String name;
        int age;
    }
}

l5z1-view.fxml

<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
        <Label text="${controller.actors.get(index).getName()}" for="index : actors" />
        <Button text="添加群众演员" onAction="#addActor" />
</VBox>
  • 直接遍历数字
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
        <Label text="${index}" for="index : 10" />
</VBox>
  • template 遍历
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
        <Template for="index : actors">
                <HBox>
                        <Label text="${controller.actors.get(index).getId()}"  />
                        <Label text="${controller.actors.get(index).getName()}" />
                        <Label text="${controller.actors.get(index).getAge()}" />
                </HBox>
        </Template>
        <Button text="添加群众演员" onAction="#addActor" />
</VBox>
  • 监听数据编号
    L6ListenerComponent代码
@FXMLPath("/base/l6-view.fxml")
public class L6ListenerComponent extends AbstractVue4jComponent {

    @FXML
    StringProperty counter = new SimpleStringProperty("0"){
        {
            addListener((observableValue, number, newNumber) -> {
                System.out.println("数字发生变化:" + newNumber);
            });
        }
    };

    @FXML
    void add(){
        int  n =Integer.parseInt(counter.get()) + 1;
        counter.set("" + n);
    }

}

l6-view.fxml

<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
        <Label text="${counter}" />
        <Button text="点我" onAction="#add" />
</VBox>
  • 事件处理,这个我们已经很熟悉了
@FXMLPath("/base/l7-view.fxml")
public class L7ActionComponent extends AbstractVue4jComponent {

    @FXML
    public StringProperty counter = new SimpleStringProperty("0");

    @FXML
    void add(){
        int  i = Integer.parseInt(counter.get());
        counter.set("" + ++i);
    }

    public void sub(){
        int  i = Integer.parseInt(counter.get());
        counter.set("" + --i);
    }
}
  • l7-view.fxml
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
        <Label text="${counter}" />

        <Button text="事件绑定" onAction="#add" />
        <Button text="内联表达式绑定" onAction="${controller.sub()}" />
</VBox>
  • 组件
    定义一个简单的按钮组件,我们这里直接把fxml代码写在代码中
public class L11RedButton extends AbstractVue4jComponent {

    @Override
    public CharSequence render() {
        imports(Button.class);
        return "<Button text=\"红色按钮\" onAction=\"#hi\" style=\"-fx-background-color: red\" />";
    }

    @FXML
    void hi(){
        System.out.println("红色按钮被点击");
    }
}

使用自定义的组件,我们这里还是直接把fxml代码写在代码中

public class L11ComponentBox extends AbstractVue4jComponent {
    @Override
    public CharSequence render() {
        imports(VBox.class, Label.class,L11RedButton.class);
        return "<VBox>\n" +
                "        <Label text=\"组件系统让我们可以用独立可复用的小组件来构建大型应用\" />\n" +
                "        <L11RedButton />\n" +
                "</VBox>";
    }
}
  • 组件传参,复杂一点的组件就不方便写在代码里了
    定义一个带标签的输入框组件,重新setProps方法接收参数
@FXMLPath("/comp/label-text-field-view.fxml")
public class L11Z1LabelTextField extends AbstractVue4jComponent {
    @FXML
    StringProperty labelText;
    @FXML
    StringProperty fieldText;

    @Override
    public void setProps(Map<String, Object> props) {
        super.setProps(props);

        this.labelText = (StringProperty) props.get("labelText");
        this.fieldText = (StringProperty) props.get("fieldText");
    }
}

label-text-field-view.fxml

<Pane>
        <Label text="${labelText}"   />
        <TextField text="${fieldText}" />
</Pane>

使用这个组件,并给组件传递参数

@FXMLPath("/comp/l11z2-view.fxml")
public class L11Z2Box extends AbstractVue4jComponent {
    @FXML
    StringProperty labelText = new SimpleStringProperty("父组件参数");
    @FXML
    StringProperty fieldText = new SimpleStringProperty("父组件参数值");
}

使用props传递参数

<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
        <Label text="组件化传参" />
        <L11Z1LabelTextField props="labelText,fieldText" />
</VBox>

更多示例可以在源代码的test中查看

git仓库

https://gitee.com/ichiva_admin/vue4j-core.git

参与贡献

  1. Fork 本仓库
  2. 新建 Feat_xxx 分支
  3. 提交代码
  4. 新建 Pull Request
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容